Curso R: Clase 1
Visión General de una base
Cargamos bibliotecas (library)
#
#{width=width='100px' height=width='100px'}
library(readxl) #lectura de archivos en Excel
library(readr) # para leer datos de texto rectangulares
library(dplyr) # manejo de datos
library(tidyverse) # manejo de datos
library(DT)
library(kableExtra) # hacer tablas bonitas
library(lubridate) # manejo de fechas
library(nycflights13) # archivo de datos de vuelos
library(googlesheets4) # para leer desde el Google Drive
library(foreign)
library(utf8)
Los Chunks
En los Chunks nos puede interesar configurar que no nos envie
mensajes o que no muestre el código o bien que no muestre la ejecución
de un código. A continuación cómo hacerlo:
cache=FALSE, message=FALSE,
warning=FALSE, sirven para que los comandos que mandan
mensajes no los impriman en pantalla. Esto es importante si queremos que
nuestros lectores no sepan lo que está corriendo por detrás.
eval = FALSE, sirve para que los códigos se
muestren, pero que no se ejecuten. Esto es útil cuando escribimos
tutoriales de R pero no queremos que se ejecute lo que hay
dentro.
echo = FALSE, sirve para que los códigos se
ejecuten pero no se muestren. Esto es útil cuando estamos escribiendo un
artículo y queremos que nuestro código se ejecute (por ejemplo, para
crear una gráfica o un mapa) pero no queremos que los lectores vean las
tripas, o el código que lo genera.
Leamos un archivo xlsx desde una ruta y lo visualizamos
baseIMC <- read_excel("../../IMCinfantil.xlsx")
baseIMC
cómo podemos acceder a una columna (variable) - modo clásico
baseIMC[,4] # accedemos a la cuarta columna
baseIMC$PESO # accedemos a la misma columna pero por su nombre
## [1] 24.4 23.6 47.0 24.0 23.9 41.0 32.9 22.4 28.7 31.4 28.9 51.2 26.2 58.5 23.7
## [16] 25.5 49.7 39.6 42.5 21.6 38.0 26.6 20.4 23.7 21.4 45.7 51.3 28.0 26.9 43.9
## [31] 25.7 28.2 36.8 27.3 33.8 23.5 33.1 37.5 33.2 36.8 29.2 30.6 28.1 23.5 19.8
## [46] 23.6 26.0 37.6 25.5 40.0 80.8 30.0 44.9 51.6 27.0 40.0 32.3 24.5 48.5 43.5
## [61] 42.6 38.0 23.9 52.0 55.2 48.0 50.5 19.0 32.0 33.5 38.0 24.5 31.5 21.2 19.9
## [76] 26.7 23.0 46.3 38.2 21.2 24.2 24.3 30.0 37.3 49.4 24.7 35.0 22.3 35.5 38.4
## [91] 32.2 40.3 40.5 59.5 43.0 20.3 22.0 58.0 37.5 41.3 18.5 19.1 32.5 34.6 29.6
## [106] 33.8 42.3 31.0 23.4 21.5 21.3 39.5 31.5 30.3 22.3 60.2 23.6 22.6 27.5 34.2
## [121] 46.5 54.8 22.6 30.3 19.7 35.4 20.8 40.2 57.3 45.5 28.4 34.6 26.4 35.0 23.7
## [136] 26.4 52.4 32.6 41.1 23.3 38.2 25.5 33.1 21.6 32.9 52.9 26.5 21.5 21.5 23.6
cómo podemos acceder a una fila (registro)- modo clásico
baseIMC[3,]
baseIMC[baseIMC$PACIENTE=="3",]
cómo podemos acceder a un dato (fila y columna especificas)
baseIMC[3,2]
baseIMC[baseIMC$PACIENTE=="3",2]
Cuál es la diferencia entre ambas
salidas?
Leemos datos desde una url
url.dat <- "http://bit.ly/Database-Estudiantes" # La url desde drive
estudiantes <- read.delim(url.dat)
estudiantes
Ordenar: arrange()
Ordena las filas de menor a mayor valor de la variable elegida.
Si escribimos un signo menos, ordena de mayor a
menor.
Por ejemplo para ordenar de la base de estudiantes en función de la
Edad:
- El primer ejemplo ordena la base de estudiantes en función de la
Edad de menor a mayor
- El segundo ejemplo lo hace de mayor a menor
- El tercer ejemplo ordena primero por Edad y segundo por la nota de
la evaluación Final
- El cuarto ejemplo lo ordena en forma creciente de edad y decreciente
de nota de evaluación final
arrange(estudiantes, Edad)
arrange(estudiantes, -Edad)
arrange(estudiantes, Edad, Final)
arrange(estudiantes, Edad, -Final)
Sintaxis en cadena
El paquete incorpora una sintaxis encadenada que permite escribir las
acciones en un orden natural, en oposición a la forma anidada en la que
lo haríamos normalmente.
Primero se escribe el nombre del fichero y luego las
acciones
En el orden en que se realizan separadas por el operador %>% (que
podríamos leer como entonces ). Este operador se denomina “pipe” y se
traduce como caño. Por ejemplo, si queremos seleccionar las
variables que contienen las medidas del pétalo, seleccionar los lirios
para los que la longitud del pétalo es mayor que 4 mm y ordenarlos de
menor a mayor longitud del pétalo, podemos escribir:
estudiantes %>%
select(contains('P'))%>%
select(-contains('A')) %>%
filter(P1 > 4)%>%
arrange(P2)
Para seleccionar las variables numéricas solamente
estudiantes %>%
select_if(., is.numeric)
Para seleccionar las variables que son de tipo caracter
solamente
estudiantes %>%
select_if(., is.character)
Podemos seleccionar algunos registros con slice()
baseIMC %>%
slice(1, 11:13, 21)
#- Nos quedamos aca
Ejercicio 1
Explica con tus palabras la secuencia anterior.
Respuesta: slice(1, 11:13, 21): selecciona las filas 1, del 11 al 13
y la 21.
Ejercicio 2
Con la base de IMC que vimos al principio.
- Seleccionar las variables Peso, Talla e IMC.
select(baseIMC, PESO, TALLA, IMC)
- Seleccionar los registros de las mujeres.
filter(baseIMC, SEXO=='F')
- De los registros de las mujeres, seleccionar las variables Edad y
CatPeso.
baseIMC %>%
filter(SEXO == 'F')%>%
select(SEXO,EDAD,CatPeso)
- De los registros de las mujeres, seleccionar las variables Edad y
Catpeso y luego ordenarlos en forma creciente por Edad.
baseIMC %>%
filter(SEXO == 'F') %>%
select(SEXO,EDAD,CatPeso) %>%
arrange(EDAD)
- Ordenar la base en forma decreciente por IMC.
baseIMC %>%
arrange(-IMC)
- De la base ordenada en forma decreciente por IMC, seleccionar los
que tienen sobrepeso y quedarse con las columnas de Edad, Talla y
Peso.
baseIMC %>%
arrange(-IMC) %>%
filter(IMC > 30) %>%
select(IMC, EDAD, TALLA, PESO)
- Seleccionar las variables Talla, IMC y CC y filtrar los registros 1,
5, 6, 7 y 15. Guardar esto en una base que se llame baseIMC_aux y
mostrar cómo es la nueva base.
baseIMC_aux <- baseIMC %>%
select(TALLA, IMC, CC) %>%
slice(1,5:6,5)
baseIMC_aux
Añadir nuevas variables: mutate()
Seguimos con las acciones básicas implementadas en la biblioteca
dplyr.
Veamos como crear nuevas variables que son función de las ya
existentes.
En este ejemplo creamos una variable que corresponde al cociente
entre la Talla y la CC (que podría corresponder a algún aspecto de la
forma de la persona de interés para su riesgo cardiovascular) en la
baseIMC:
baseIMC<-baseIMC %>%
mutate(forma = TALLA/CC)
baseIMC
Observemos que la nueva variable forma
aparece en la última columna.
Podríamos redondear los valores de esta
nueva variable, por ejemplo con tres cifras decimales.
baseIMC<-baseIMC %>%
mutate(forma = round(TALLA/CC,3))
baseIMC
Resumir (subconjuntos de) variables: group_by() + summarise()
Usamos summarise() para aplicar comandos a variables.
Normalmente se usa en combinación con group_by() de manera
que se calculen estadísticos para subgrupos de observaciones.
En el siguiente ejemplo se calcula la media del IMC para cada
categoría de Peso:
resumen1<-baseIMC %>%
group_by(CatPeso) %>% summarise(Media_forma=mean(forma),n=n(),stdev=sd(forma)) %>% mutate_if(is.numeric, ~round(., 4))
resumen1
Hay distinas posibilidades que nos permiten visualizar las variables
su tipo y algunos valores, veamos similitudes y diferencias
glimpse(baseIMC)
## Rows: 150
## Columns: 10
## $ PACIENTE <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18…
## $ EDAD <dbl> 7, 7, 8, 7, 7, 10, 7, 7, 7, 9, 9, 11, 7, 9, 9, 11, 12, 7, 11,…
## $ SEXO <chr> "M", "M", "M", "F", "M", "M", "M", "M", "M", "M", "M", "F", "…
## $ PESO <dbl> 24.4, 23.6, 47.0, 24.0, 23.9, 41.0, 32.9, 22.4, 28.7, 31.4, 2…
## $ TALLA <dbl> 1.2, 1.2, 1.4, 1.2, 1.2, 1.4, 1.3, 1.2, 1.3, 1.3, 1.3, 1.6, 1…
## $ IMC <dbl> 16.94444, 16.38889, 23.97959, 16.66667, 16.59722, 20.91837, 1…
## $ PIMC <dbl> 7.97, 72.72, 97.08, 83.88, 45.85, 87.33, 96.57, 32.88, 80.77,…
## $ CC <dbl> 54, 52, 76, 63, 56, 78, 69, 52, 60, 69, 60, 75, 50, 88, 58, 7…
## $ CatPeso <chr> "N", "N", "OB", "N", "N", "SO", "OB", "N", "N", "SO", "N", "N…
## $ forma <dbl> 0.022, 0.023, 0.018, 0.019, 0.021, 0.018, 0.019, 0.023, 0.022…
summary(baseIMC)
## PACIENTE EDAD SEXO PESO
## Min. : 1.00 Min. : 6.000 Length:150 Min. :18.50
## 1st Qu.: 38.25 1st Qu.: 7.000 Class :character 1st Qu.:23.93
## Median : 75.50 Median : 8.000 Mode :character Median :31.45
## Mean : 75.50 Mean : 8.327 Mean :33.40
## 3rd Qu.:112.75 3rd Qu.: 9.000 3rd Qu.:40.00
## Max. :150.00 Max. :12.000 Max. :80.80
## TALLA IMC PIMC CC
## Min. :1.100 Min. :13.26 Min. : 2.02 Min. : 50.00
## 1st Qu.:1.200 1st Qu.:16.27 1st Qu.:53.02 1st Qu.: 56.25
## Median :1.300 Median :17.77 Median :79.75 Median : 63.00
## Mean :1.322 Mean :18.60 Mean :68.56 Mean : 65.25
## 3rd Qu.:1.400 3rd Qu.:20.86 3rd Qu.:91.23 3rd Qu.: 72.75
## Max. :1.700 Max. :31.56 Max. :99.27 Max. :107.00
## CatPeso forma
## Length:150 Min. :0.01500
## Class :character 1st Qu.:0.01900
## Mode :character Median :0.02100
## Mean :0.02056
## 3rd Qu.:0.02200
## Max. :0.02600
str(baseIMC)
## tibble [150 × 10] (S3: tbl_df/tbl/data.frame)
## $ PACIENTE: num [1:150] 1 2 3 4 5 6 7 8 9 10 ...
## $ EDAD : num [1:150] 7 7 8 7 7 10 7 7 7 9 ...
## $ SEXO : chr [1:150] "M" "M" "M" "F" ...
## $ PESO : num [1:150] 24.4 23.6 47 24 23.9 41 32.9 22.4 28.7 31.4 ...
## $ TALLA : num [1:150] 1.2 1.2 1.4 1.2 1.2 1.4 1.3 1.2 1.3 1.3 ...
## $ IMC : num [1:150] 16.9 16.4 24 16.7 16.6 ...
## $ PIMC : num [1:150] 7.97 72.72 97.08 83.88 45.85 ...
## $ CC : num [1:150] 54 52 76 63 56 78 69 52 60 69 ...
## $ CatPeso : chr [1:150] "N" "N" "OB" "N" ...
## $ forma : num [1:150] 0.022 0.023 0.018 0.019 0.021 0.018 0.019 0.023 0.022 0.019 ...
Otros resúmenes como desvío standard y cantidad de registros
baseIMC %>%
select(TALLA,SEXO) %>%
group_by(SEXO) %>%
summarise(Total_Registros=n(),
media_talla=mean(TALLA),
sd_talla=sd(TALLA)) %>%
arrange(-media_talla)
Para que muestre algunos registros de los
primeros usamos head() Para que muestre
algunos registros de los últimos usamos tail().
estudiantes %>% arrange(desc(Final)) %>% head(8)
estudiantes %>% arrange(Final) %>% tail(8)
Para agregar una nueva fila a la base de datos podemos utilizar
add_row():
baseIMC1 <- baseIMC %>% add_row(PACIENTE= 151, EDAD = 12, SEXO="M", TALLA=1.3,IMC=16.7,CC=75)
baseIMC1
Observen qué ocurrió con las
variables que no cargamos!!
Otra característica importante es el conteo, podríamos estar
interesados, dado un conjunto de clases cual es su frecuencia absoluta
de cada categoría, para esto utilizaremos count() el cual genera una
variable que contiene dichas frecuencias.
Ahora eliminamos la/s fila/s que tengan algún registro faltante
baseIMC1 %>% na.omit()
baseIMC %>% count(CatPeso)
#table(baseIMC$CatPeso)
baseIMC%>%summarize(n_distinct(CatPeso))
#length(unique(baseIMC$CatPeso))
Podemos utilizar el condicional ifelse() para crear nuevas variables
según ciertas condiciones:
baseIMC2<-baseIMC %>% mutate(categoría = ifelse(EDAD > 10, "Mayor", "Menor"))
baseIMC2
Renombrando variables
También podemos cambiar el nombre a una variable.
estudiantes %>%
rename(Gasto_total = Gastos)
#- Tambien tenemos estas opciones
#names(df)[names(df) == 'old.var.name'] <- 'new.var.name'
#colnames(df)[position] <- "newname2"
Cuando quiero cambiar el nombre de todas las columnas
setNames()
baseIMC3<-baseIMC %>%
setNames(c("Paciente", "Edad", "Sexo","Peso","Talla","BMI","BMI_perc","PC","Cat_Peso","Forma"))
baseIMC3
Ejercicio 3
Con los datos de Admisión, cuyas variables indican si el estudiante
fue admitido (categoría 1) en una carrera de posgrado, el puntaje del
estudiantes en GRE (graduate record exam scores-puntajes de exámenes de
registro de posgrado) y GPA (grade point average- promedio de
calificaciones de la carrera de grado) y el rank(rank of the
undergraduate school- rango de la escuela de pregrado).
admision <- read.dta(url)
head(admision,8)
admision
- Crear una nueva variable que promedie los valores de gre y gpa.
- Agrupar por rank y promediar gre y gpa para cada rank.
- Extraer una muestra de 100 registros sin reposición de dos maneras
distintas.
- Resumir las variables de la base
- Agregar una fila que resulte muy diferente a las otras y no colocar
rank.
- Eliminar los registros que tengan algún valor faltante.
- Contar cuántos fueron admitidos y cuantos no.
- Contar cuántos hay de cada rango de escuela.
- Cambiar el nombre de una las variables (sean creativos!).
- Cambiar el nombre de todas las variables (pónganle humor!).
Cambiar niveles de un factor
En la base de estudiantes queremos recodificar la variable Fuma
df <- estudiantes[1:40,1:10]
df<- df %>% mutate_at("Fuma", factor)
levels(df$Fuma)[1] <- "0"
levels(df$Fuma)[2] <- "1"
df
Estilo Oscuro
resumen1 %>%
kbl() %>%
kable_material_dark()
|
CatPeso
|
Media_forma
|
n
|
stdev
|
|
D
|
0.0223
|
6
|
0.0023
|
|
N
|
0.0216
|
90
|
0.0016
|
|
OB
|
0.0177
|
27
|
0.0012
|
|
SO
|
0.0195
|
27
|
0.0019
|
tidyr
gather()
spread()
separate()
unite()
dplyr
select()
filter()
group_by()
summarise()
arrange()
join()
mutate()
El archivo flights está disponible en R y contiene información
relativa a salidas de vuelos de NYC en 2013
flights %>%
select(year, month, day, hour, minute)
Armamos una fecha a partir de tres variables
flights %>%
select(year, month, day, hour, minute) %>%
mutate(hora_partida = make_datetime(year, month, day,hour,minute)
)
Fusiona tres columnas: year, month y day en una nueva columna
“fecha”.
vuelos<-flights %>% unite("fecha", year,month, day, sep = "/")
vuelos
La función separate() separa en dos columnas la fecha
vuelos %>%
separate(fecha, into = c("año", "mes"))
vuelos %>%
separate(fecha, into = c("año", "mes"))%>%
unite("campo",año,mes,sep="-")
Vamos a ver como darle nueva forma a una base de datos según el
análisis que querramos implementar puede ser necesario
#Cargamos dos bases de datos: la primera tiene el nombre y el apellido de los músicos conjuntamente con el
#instrumento que ejecutan principalmente.
artistsKH <- tibble(first = c("Jimmy", "George", "Mick", "Tom", "Davy", "John", "Paul", "Jimmy", "Joe", "Elvis", "Keith", "Paul", "Ringo", "Joe", "Brian", "Nancy"), last = c("Buffett", "Harrison", "Jagger", "Jones", "Jones", "Lennon", "McCartney", "Page", "Perry", "Presley", "Richards", "Simon", "Starr", "Walsh", "Wilson", "Wilson"), instrument = c("Guitar", "Guitar", "Vocals", "Vocals", "Vocals", "Guitar", "Bass", "Guitar", "Guitar", "Vocals", "Guitar", "Guitar", "Drums", "Guitar", "Vocals", "Vocals"))
artists <- artistsKH
artists%>%head()
# La segunda base tiene el nombre y el apellido de los artistas conjuntamente con la banda donde se hicieron famosos.
bandsKH <- tibble(first = c("John", "John Paul", "Jimmy", "Robert", "George", "John", "Paul", "Ringo", "Jimmy", "Mick", "Keith", "Charlie", "Ronnie"), last = c("Bonham", "Jones", "Page", "Plant", "Harrison", "Lennon", "McCartney", "Starr", "Buffett", "Jagger", "Richards", "Watts", "Wood"), band = c("Led Zeppelin", "Led Zeppelin", "Led Zeppelin", "Led Zeppelin", "The Beatles", "The Beatles", "The Beatles", "The Beatles", "The Coral Reefers", "The Rolling Stones", "The Rolling Stones", "The Rolling Stones", "The Rolling Stones"))
bandsKH%>%head()
Juntamos dos bases utilizando una o dos variables en común con
left_join()
bands2 <- left_join(bandsKH, artists, by = c("first", "last"))
bands2 %>% head()
Observen Qué diferencia hay con
right_join()
bands3 <- right_join(artists, bandsKH, by = c("first", "last"))
bands3 %>%head()
artists
bandsKH
# inner_join solo retiene las filas que estan en ambas bases
bands4 <- inner_join(bandsKH, artists, by = c("first", "last"))
bands4
# full_join retiene las filas de cualquiera de las bases aunque no estén en la otra
bands5 <- full_join(bandsKH, artists, by = c("first", "last"))
bands5
Pasando de formato ancho a formato largo y viceversa
# En esta primera base hay tres columnas para cada empleado en las columnas están los salarios medios de tres años de trabajo
data_2 <- data.frame("names" = c("Pedro", "Carla", "Marta"),
"W_2014" = c(100, 400, 200),
"W_2015" = c(500, 600, 700),
"W_2016" = c(200, 250, 900) )
data_2
# En esta segunda base estan los mismos datos pero ahora para cada año y para cada empleado hay un registro donde esta su salario
data_3 <- data.frame(names = c("Pedro", "Carla", "Marta", "Pedro", "Carla", "Marta", "Pedro", "Carla", "Marta"), year = c("2014", "2014", "2014", "2015", "2015", "2015", "2016", "2016", "2016"), salario = c(100, 400, 200, 500, 600, 700, 200, 250,900))
data_3
Ejerccio 4
Con las bases de datos Clientes.xlsx y Registros.xlsx se pide:
- Separar la variable Cliente en dos variables: Apellido y
Nombre.
- Unir ambas variables en una sola que se llame ID y separar apellido
y nombre con “-”.
- Unir las bases de Clientes y Registros dejando las fechas al final y
guardarlo en una nueva base.
- Ídem pero dejando la fecha al lado del nombre y guardarlo en una
nueva base.
- Seleccionar de la ultima base, los registros correspondientes a
PIMES y elegir a los últimos 10 que se atendió, guardarlo en una tabla y
presentar una tabla bonita como salida
Ejercicio 5
Con los datos de la base consumo_oxigeno.xlsx a) Colocar en una
variable el día y en la otra el consumo. Guardar en una nueva base de
datos. b) A la nueva base de datos volverla al formato anterior.
LS0tDQp0aXRsZTogIkNsYXNlIDEgSW50cm8gUiBBdXN0cmFsIg0KYXV0aG9yOiAiRMOpYm9yYSBDaGFuIg0KZGF0ZTogIkFicmlsLTIzIg0Kb3V0cHV0Og0KICAgaHRtbF9kb2N1bWVudDoNCiAgICAgdG9jOiB5ZXMNCiAgICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgIHRvY19mbG9hdDogeWVzDQogICAgIGRmX3ByaW50OiBwYWdlZA0KICAgICB0aGVtZTogdW5pdGVkDQogICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCmVkaXRvcl9vcHRpb25zOiANCiAgbWFya2Rvd246IA0KICAgIHdyYXA6IDcyDQotLS0NCiFbKipDdXJzbyBSOiBDbGFzZSAxKipdKGRhdGE6aW1hZ2UvanBlZztiYXNlNjQsLzlqLzRBQVFTa1pKUmdBQkFRQUFBUUFCQUFELzJ3Q0VBQW9IQ0JVU0VoUVZGaFVaRlJZWkdCb2FHaHdTR0JvaEdCa1ZKUmtjR2h3ZUhoWWRJUzRtSGg4dExSZ2pKamdtS3k4eE5UVTFHaVk5UURzMFB6QTBOVFlCREF3TUVBOFFIeElTSHpRckpTdzNORFUwTkRFM05UUTBORFUyTkRRL05EUTBQVFEwTkRRL05ERTBNVFEwTkRRME5EUXhORFEwTkRRME5EUTBORFkwTlAvQUFCRUlBT0VBNEFNQklnQUNFUUVERVFIL3hBQWNBQUVBQWdNQkFRRUFBQUFBQUFBQUFBQUFCUWNEQkFZQkFnai94QUErRUFBQ0FRTURBZ1FEQXdnTEFBTUFBQUFCQWdBREJCRUZFaUV4UVFZVElsRUhZWUV5UW5FVUl6UnljNUdoc1JVek5WSmlkSUtEc3JQd2tzUFIvOFFBR2dFQkFRRUJBUUVCQUFBQUFBQUFBQUFBQUFFQ0F3UUZCdi9FQUNvUkFRRUFBZ0lDQWdBRkF3VUFBQUFBQUFBQkFoRURFaUV4QkVFVE1tRnhrVkdCOEJRaUl6T3gvOW9BREFNQkFBSVJBeEVBUHdDdVlpSitnZWNpSWdJaUlDSWlBaUlnSWlJQ0lpQWlJZ0lpSUNJaUFpSWdJaUlDSWlBaUlnSWlJQ0lpQWlJZ0lpSUNJaUFpSWdJaUlDSWlBaUlnSWlJQ0lpQWlJZ0lpSUNJaUFpSWdJaUlDSWlBaUlnSWlJQ0lpQWlmU3FTUUFNa25BQTZrOWhqM2tucG1tbzlRVTNZaW8yUWlJVktzK3plZ2FvQ1FBeDlIQUp5UjBrdVVudFVWRTZUdzFhMHFvY3ZUWEg1VGJvUE1CSjJ1S3dLYnhqYVNVUWJ1eDVrZnBPanZjVkNuTk5RU0dabEoyRUFrakhHU01jOUFPL1VaejNtN3Y2VFNMaWVxQ1JuQnh4bjVaNlpQMC9oUEpzSWlJQ0lpQWlJZ0lpSUNJaUFpSWdJaUlDSWlBaUlnSWlJQ0NZbWV5dW1vMUVxSWNNaHlQNUVmVVpIMWdUR2sySllicUQwNmxUWUhBK3pXcFZrTzlkcU5qZWgyaFNWM2NrWkFBbXRlYXVIU2x0VkE2T3RSV1NoVHA3Q0Fjb3V3ZXRTY05rampBNG5tdDNxVkRoVXBjN1dEb20xOXBYTzExWENGODlXQzlmcklxY3NjZCtjbDJ5MTdoNmpNenNXWmlXWTlNdDc0SEV6Mm1vUFRaVyszdFdvcWh5U0ZEcVZjcnp3ZlVmcjJtbkU2WEdYd0ppczRGQktWdmtxNVh6T25tMWEzTzFEVEJMYkYrN2pJSmJPYzhEUzFDejhsd2haR2ZBM2hEblkvM2tMZEN3NzdTUm5JN1RIYTNUMG1MSTVSaXJMbFRnN1dHRHoyNjllc2xucjBLVnNVUXEvbVZTZHZCY1VmSjJydmJiNlNITzRLT3ZQYkJuUHpqUkJSRVRxaEVSQVJFUUVSRUJFUkFSRVFFUkVCRVJBUkVRRVJFRFBaVy9tVkVUZXFiampkVU9FQjdaUFlkdnJOeTgwNnZiVTNEb3V4M1ZkNnNqamN1NDdWZFNjZHlSd2ZRUGFZdE5aRTN2VXR6WFFZWDdicXFPY2tFbE9wNHdBU0FlWmsxbThTb1VLQlZHd0FoRWRUd1NGMzduZmN3SGZQUTRuTzI5dGZTbzBtZGo0YytIdHpkNGR2ekZQS0hOUVpaMFpkMjVBT0R3UjFJNVB5blMvRGp3TzZPTHE1WGFSdlZLVHFNL2VSbWNFZDg4WTdmakxTUk1BQUFBRGdBZEFKNU9mNWRsNjRmeTNqai9WWHR2OEtiVUlxdFVxT3dZa3NwQXlwVURianBnSDFaNjlwQVhud3RxL2xGWUl3RnVFWjZUWnk1ZkEyVTJISGZQSTdBZHpMUTBtMHJVMnJtclc4MFBVTElOb0d4Tm9HMytIL3N4cmx2WHFVdHR2VVdrKzVEdWRkdzJoZ1dHTWp0Ky9weG5JODJQeU9TWDh6VnhqODhhcm8xeGFNRnIwbnBrNHdXR1ZKeG5BZGNxVHowQjRtcGJWalRkWEFWc2RuR1ZJeGdnanVDRGlmbzdYOUgvTExSN2RuMmx3b0xxb3p3d1k0QjZaMi94bjUrMTJ6VzJ1NjlKUVN0T29WWHpBQ1NvT1J1SFE1L2lEUGQ4ZjVINHNzdnR6eXgwMXpZT3RGYXpEQ00yMWR4QVordVdWZXJLTVlMRGpKQTk1cXpvcXlWYmsxbmY4bkpXbnVkdHh5aWhmUUJ0WXFuWlZYams0QW5PejBZWlcrMmFSRVRRUkVRRVJFQkVSQVJFUUVSRUJFUkFSRVFFUkVDUzB5N1NrQzVTbzdodnVWTmliQ0FBSEFRbHNrSGpJQjQ2ellzYVhuYWhSUnJjSUhxSnVvb1NnMm5CSUJkc3FTUFYxSFhqR1JQdnc5cVQweDVhVTY5VjJkbUMyOVJreUNnWDFLcU1YSXdTRHh0SnpOYS91SHBYUXFlVTlKMFpIMlhPNTIzREJ5eGNBdUNSM25DN3VWbjZOUDBxdlNhZHBxVktzOVZFcUs3VTIydUZJSlU0VnUzNncrdVIybWhvSGlTaGQwZzlPb3B3VlJzcXlnVkNCNlFHK1pIVFBVVFR0ZGZzRXZLOXVySWxkbVVzU0FCVWZZb0FEOUN3QUEyOWNnOFQ1SFRMek5WMTI2bVJOL1h1VnIyNjA2U05SWXQ1cnM1RElBcEl3dTA5L256MDQ2eUgxM3hlMWtqZWRRWlgyZzA5cExVcTFUZGcwMXFLdVEyTUgxS0NjbkE0bTlaNitWdEJjWGxNV1h1dFJ3VDE5T01ET1QvQUhjWitVZGJyWnRQeWgvaWhwS1cxOFdSdDNuQTFHRE1DeXNYT2VBQmhUMjVQMldsbjJuajNUNmliL3loRTUyN2F2cGZyZ0hZZWR2ejZjODRsVmZFSHhFbC9jSzFOM0tJR1hhNFhZR3pnc2hYa3F3QU9XbnErSmhuanlldFQ3WnlzMDE3VU9hTkJBTE5VQkZURlc0Vldkejk2cFROUVpiSEFCSEE2RGs1NXdqQk1tYkZyZmFxclNScTRJM2k3cU9FSjYraFVLZ2ZnNVAxa05uTStoeHpWcm5Ya1JFNklSRVFFUkVCRVJBUkVRRVJFQkVSQVJFUUVSRURlMDI0Vk42TzcwbGRRcGVrdTVnQTJjRmR5NVE5d0dIUWRla3kzNksxTkhwSlZhZ25vTlNxb0c1MkxOZ0FFaFFNY0xra2QrczBLRlVvNnVNRXFRY01BVk9EMEtuZ2c5Q0pOVkc4OFV2T3JYRmF0VkI4dEtLcVVwcnVaUjZPNUpRbllvWEFBNW5MTHhsdFlnUU9jOXgwUGNmV01UTGMyN1U2akk0d3lNVk9Ea1pIc2U0bjNiMnBxZmZSQjcxSENqOTNKUDBFNmVQYUxxK0dPcU5lV08ydCtjZWhVMkJuNUpBQ3VqRW43dzNZejE0bGRmRXJWM3VOUXFvU2ZMb05zcHIyQkFHOXNlNU9SbjJBbGdmQzJuUm9Xam9LOUdyVU5ScWppaytRb3dGR2NnSG91YzQ3emdQSE5qU2UrdUt0RzV0M1YyRGJSVTlTdmdCaG5HM3FNL2E3ejUvRDFuUGZIN09sL0s1R1pyTzNOUjBRWTlSeDZtQ2pIVTVjOEx4M014dWhCSVBVZXhCSDd4d1pNNkxZTzFOcXFxaHdTaGF1S1JvVTFBVmlhbm1BNDNic0xnWjRPTXozNTNVMnhHNXFtb1ZBSFN2VFlOaXBzRnhSUm1DdGhhZXlydHlvVVpJSUpCbk1TWDF2VUhiRkZnRkNNQ3dSeTFObjJCUXlKOWxGSTUycng2dndBaUpuam1vVWlJblJDSWlBaUlnSWlJQ0lpQWlJZ0lpSUNJaUFpSWdKSTJOKzZvMUVWUlJSc2xuQ25lVnhrcHZVYnRwNjdjZ0VubnJJNkpMSlo1VkphaFowNlZLaVFYTlJ3WHc0VUJhUFJDVUdTcFlna0RjZlNBZnZDUnhHT0R3Zm5KU3dyVXFsUXRjRXU0d1J2YkNWTnFCVVIyUDJGNEdXNXlCamc4ekxTb203OCt2VnFIY3JJRHNWZUVaaXBxRmVQemFlbGNEa2JsNkNZbVhYMmEyaGYvZlNKOU12Snh5Qm5rZE1lLzRTWDB2Um1xMHpWU205YkRNTmxJYnNNb1ZnSEFZTUZmT0J0NTRQUGFhdG1NM1JvMk5tS2pCWGNVZ3diWXpnaEdjRGhkK01LTWtaWThETWtidW9RcE54Uk5PNHBuWWpvcUtXZEFtRXFVOGJXQVZnUTRISXdQVU9SOFgxZTNlZ05tVWRYM2VVK1dDN3Z0aEg2RlBTdnBJRERCKzFuTWpyeTdlcXdMSDdLaEZVRTdVUWRGWEpKQUg0ekdybmRucGlkeXhMTWNrbkpKNmt6NGlKMVFpSWdJaUlDSWlBaUlnSWlJQ0lpQWlJZ0lpVDFob2FWVzA1UzdEOHFhb3JZQTlHMm9hWTIrL1RQTXpsbE1mYW9HSnY2UFpwV3VWcE81UkQ1bTUxR1NxclRkODdlLzJPa3phcG9yMjFQYzV5M21sRks4bzlQWXJxNk4zRGJ2OEF4ekhmSGZWTklxSklYV25oTFczcjdpVFZhc3BVNHd1eGxBSVB6M2Z3bTNRMFZYbzBhNFp2TEsxdk9PQm1teURjRkh2dkRMdHozYjVTZmlZei93QVhTRW0xU3YzUkdRTmhTcklmU3VkakVNeWhpTWdFakpBbTM0ZjAxYmw2aXNXR3lnOVhGUGJ1WXJ0OUlMY0RPN3FacDNGRUxWS0FNbzNCY1ZOcFlkTTVLOGQrMHR5bHVoaXAxblRkdGRsM0RhMjFpTnkreHgxSHlNOXRxNXB0dkNxV0gyUzY1MnRrRU12c3dJL25KN3hUNGVTeXdBN2x2TmRBdFJWQmRGQS9PS1ZQMk1uYmdqT1IzbXRvdWtwWHBWV3k3dWhINXFpVURtbmdscWdEZmJDa0FGVjU1ek16UEM0OXZvMWQ2UTdNU1NUeVNja251ZTgrWkk2RFlDNnJyU1ppb0tPMlZBejZhYlAwUHZ0eDlZMEd4VzVxTXJzeXF0S3JVT3pHZlFoZkF6eHpqRXR6azMraHBIUkpHLzA1VW8wYTlObWFsVVoxdzRBZEtpNDNLY0VoZ1F3SVllL1FUWXNOQ05XMXIxd3hESUN5THQ0ZEVLZWEyN3R0RGdnZDlyZTBmaVk2MmFRMFNSMEhUMXVhL2x1ekt1eW81S1l6NmFiUGpuam5iajZ6MiswOVZvVXJpbXpOVHFNNlljQU9sUlFDVk8wa01DR0JCR1B3RWQ1MjZwcEd4RVRZUkVRRVJFQkVSQVJFUUVTWjhJNlorVlgxdlNLaGxMNWNObkhscU56WndRZWd4K0pFN240a2VEYmVoYXJYdHFZVFl3RGhTeERJM0FQSlBRNCtoTTQ1OCtPT2N3djJzeDNOcXRrenAzaUtwUVdpQWxKMm9PelVtcUt4Wk54M01CaGdDTThqSU9NOFNHbHNlRHZEbG5YMG9YRlMzUnFpcld5MjV4dTJzd1VrQnZaUm1Ubnp4d2t1VTJZeTMwcSsydW1wMU42Z2JzT1BVRGpEb3lOeG4yYzQra3lWdFNxUFFwMjdOdXAwMlprQjZydUFCQVA5M2pPT3hKbW1Heno3ODhkSlp2d3c4UFdsN2JWV3IwRmRxZGJZR0xPQ1YySzNPR0E0M0dYbHl4d3g3MkVtN3BYdGErWjZOS2ljYktUT3lZQjNaY3FXeWM4L1pHT0o1UjFDb2xHclFWc1U2akl6cjdzbWR2NGRlZmZhUGFUT2o2RUwzVW50MXhTVHpLdWRuM0tTTVJoYzU1NEE1OTh6cS9GRjVZNlRWVzNwNmRTcnY1YXV6M0J5Y0VzQU56S3hZK2s1NkNaeTVaTE1aanUzeXNuMnIzVHRRYWd6c3FvKyttOUpoVURGU2pZM0Qwc3BCNDY1bUI2b0xoZ2lKakdGcDd0dkg2ekU5dmVkUHErc1dGMWExTnRtbHBkS1VLR2tjbzQzZ01PQXVEZ2s0STdkWmwwdlZkSXAwYWExYk9yWHFoUnZjRUFNL1U0SG1EZ2RCeDJsNzMzMXV6WDZvTy8xNnJjTFZXb0VZVktwcmZaUDV1b1JoaWgzZWtNT29PUWNlOHhhWHFqV3pLeUlocUkyOUhjUHZSc1krNndERDVNQ09UN3kyUEMyaDZWcU5FMWtzaWlxNVRGUm0zWkFCejZYSXg2cHlsVFc5RVhjUDZPcUVqSSsxd1QrUG1kUHBPV1BMamQ0VEcrUGMveWxuM3R4dW0zNzI5VVZVd1hBY2VzRWpESVViZ0VjNFl6elRMOXJaeTZoV0pSMElxQWxTcktVWWVrZzlDZWN6cWZBdHRiMzJwT3RTM1FVbnBzeTAwTGJVS2xNWVlFRW5rNUo2NXp4Snp4TWRKc0x2OG5xYWVYRzFITFU2alpBWWtmWUxET052dk5aOHVNeTY5YmJvbU8vS3U3elVHcXBUUWhVcDA5MnhLWUlRRmpsbTlSSlpqZ1pKSjZDYkZucmxhaTlKa1lBVTFLQlBWNWJLZHhmZXVjTVczdGsvd0Q0SjNmaVB3TGJQWm05c1dZS0U4ell4TEs2WXlkcGIxS3dIYk9PTWNkWldNNmNXZUhKajRuOWtzc2JlbTM3VzFUekVWQ2RyTGh3U3UxbEtzTUJnZWpFZFo3ZDZnMVJLZFBDSlRwN3RpVXdRb1pzYm1PNGxtWTRISko2ZHA1cFZvMWV2U3BJTXM3cW9CNmNrWno4Z01rL0lHV3Q0NDhEV3lXTlNwYlVnbFNuNnpzWmp1UVpEcmdrOXNuOFZtZVRrd3d6a3M4MVpMWXA2SWxsZkREdy9hM3RDdWJpZ3RSa3FBS3haZ2RwUUhCMnNCMXorK2RPWGxuSGoycVNidWxheE56V1VWYm00VkZDb3RWMVZWemhWVnlvSFBQYWFjM0x1YkNJaVZDSWlBaUo5MGFUVkdWRUc1MllLbzkySkFBL2VZSGUrQndMR3d2ZFNiN1JYeWFHZTdaSEkvRmlvLzJ6T2srRzErdC9wdFd6ckhlYVlOTnM5V29zRHRQMDVIK2tTUDhBRk9yMituVXJmVG10VXV4VHBxN2VZNVVDcHo2c0JUbGpsbStXNGU4MGZDbmpXMnBYU0tsaFR0aFZaYWJ2VHFNU0FUaGNxVUdSbkhmaWZOenh5emx5Nis3dVg5STZTeVhUZzlSc1d0NjFTaS8yNmJzaCtlRHdRUFlqQkh5TXVQNGZmMkVmMWJuL0FKdk9hK01PamJLOUs2VWVtb05qNDdWRkdWUDFYai9ST2wrR2krWm94UlQ2czNDZmd4WmlQNE1EOVpybXo3OE9OL1V4bXNsSXIwSDREK1V1UDRLZm9sei9BSmovQU90SlR1d3I2U01NT0NEMUREZ2cvT1hOOEdLTExaMTJJd3IxeVZKKzhBaUtTUGxrRWZTZGZsMy9BSXY0VEg4eXRiSFdIc3RSZTRRYmlsYXFHVS9lUXV3WmM5dU8vdUJMVnY4QVQ3THhCYnJVcHZ0cUlNQmhqektaNjdIVHVQbDlRWlRtb1VIYXJkT3FrcWxXcHZJNktHcU1GejdBbmpNK05MMUtyYTFGcTBYS092Y2RDUFpsNk12eU11ZkQyMWxoZFpRbDE3YjNpUHc1Y2FmVUMxbDlMWjJ1bVNqajVIc2Y4SjUvSHJJYVhuVXU2ZXE2SlVxMVZDNXBWR1BzdFdudTlTazlzcmtmSTRsR0NiK1B5NVp5ekwzUEZaeW1sMWZCdjlBcS93Q1lmL2drcGl0OXR2MW0vbVpjL3dBRy93QkFxLzVoL3dEZ2twaXQ5dHYxbS9tWnkrUC9BTnViV1hxT3orRWY5cGo5alUvbWs2THg1NE11NzdVUE1wS2dwbW1pRm5jQUFndG4wakxIcjdUbmZoSC9BR21QMk5UK2FTUitJT3MxclBXRnEwbVliYVZJbGR4Mk9OejdsWmVoQkhHZTB6eWR2eC85bnZSTmRmTGQ4UStKNk9uMlA5RzBDMVNzdFB5blowWlZRTUR1YjFBWkp5Y0FjY2ptVlhMczhVNlBTMW14UzVvQUdzRTNVenhsdjcxSnZua0VmSWo4WlNqREdjZ2dqZ2dqa0h1TWU4MzhXNDliL1hmbE1uYy9ESzJXbTF6ZjFQNnUycHR0K2RRakp4OHd2SCs1T2srRlhpRnJuOHFvVmpsMmQ2Nmc5MWR2emk4OWdXSC9BTS9sTk8vdnFXa2FkYTJsVzNXNGVzcHExVWQ5cWc1RGNrS2M0T0ZBL3dBRWhkSThiMnR0V1dvbW0wcUpCd3owNnBMS2g0WWdiT2VPY2Q4VGpuTXVYdGxKNzlYOW1wZGVIT2VKOUlObGQxcUgzVmJLRTk2YmNyL0E0L0ZUTEorQ2Y5UmQvdFUvNnhNZnhnMGdQU28zaVlPM0NPUjNwdHlqZlFuSCs1TW53VS9xTHY4QWFyLzFpWGs1Ty94OS9malpKckpWMnRmcFZ6KzNxLzhBWTAwcHU2MStsWFA3ZXIvMk5OS2U3SDhzWUlpSnBDSWlBa3g0WDFLamEzS1Y2cVBVQ1paRnA3ZVh4Z0VsajBHYy9qaVE4U1pZekthcEcvcmVvRzZ1cTljNS9PT3pBTjFDWndpOGV5Z0Q2VFFJaUpKTlRVVllPcStQS04xcDR0YTFHb3orV2c4d0ZNZWFvR0h4bk9NamtleE1odkJYaTk5TmRnVjh5aTVCZFFRR0RBWTNxVHhuSEJCNE9CMHhPWGljNXdZVEc0NjhVN1ZaT3BlSU5EcnMxZDdTcTFWdVdWUVZETi9pQzFBaFB1ZTgyTk0rS2RPbUdWclVxZ0lGSktCUUJLWUFBQnpqSnprOERBbFhSTS82WERXcnUvM1h2WFQ2QjRtUzB1N21vYVBuVUxqY0hSOXU3YXpseDdxU01rWTZIUGFTRFZ0Q2M3dkx1NldlZGlFRmZ3QjNIQS9BemlJbXN1REczY3RuN1ZKazdYeEg0MVNwYkN5czZKb1c0RzF0eEc5bHprcmdFNEI2a2trbm42OFZFVGZIeDQ0VFdKYnQzdmdyeDFSMDYyTkZxTlNvek96a3FVQzhnS0FNblBSWncxd3lsM0s1MmxtSzdzYnRwT1JuSEdaamlURGp4eHl1VTkwdDI2RHdYcnFhZmRHNGRIZjBNZ1ZObzVZcmtrc2Y4UDhBR2UrTmRlcDZoY2l1aU1ub1ZHVnlwNVVzUVFWL1cvaE9laVB3c2UvZjdOK05PcThGZU1uMDRzaFExYURuSlVOZ3EvVGNwUEhQUWp2Z2ZYTHF1dTJGeGVVN29XOVpDSEQxRVVwdHFFY2c5ZlNTUU05aU05K1p5RVNYaHd1VnkrenRVejRzMXMzOTI5ZkRLcENxaXZqS0tGQXh4OHl4L3dCVWhvaWJ4eG1NMUJZRmo0OG8vd0JIQ3l1S05TcitiTk1zaFVlbm5aakp6bFJqbjNXYXZnWHhwUzAybFZScVZTb3p2dnlwUUFLRkNnY25yeE9KaWM3OGZEVm4xZkoycnQ3alg5SGQyZHROcWxtWXN4ODVobGljazRGVEhVelQxZlc5UGUyZW5iV0pvVkgyanpISVpsVU1HWUJpeFlFZ1k0OTV5a1JPSEdmZC9tbmFrUkU3SVJFUUVSRUJFUkFSRVFFUkVCRVJBUkVRRVJFQkVSQVJFUUVSRUJFUkFSRVFFUkVCRVJBUkVRRVJFQkVSQVJFUUVSRUJFUkFSRVFFUkVCRVJBUkVRRVJFQkVSQVJFUUVSRUJFUkFSRVFFUkVCRVJBUkVRRVJFQkVSQVJFUUVSRUJFUkFSRVFFUkVCRVJBLy9aKXt3aWR0aD13aWR0aD0nMTAwcHgnIGhlaWdodD13aWR0aD0nMTAwcHgnfQ0KDQoNCiMgVmlzacOzbiBHZW5lcmFsIGRlIHVuYSBiYXNlDQoNCiMjIENhcmdhbW9zIGJpYmxpb3RlY2FzIChsaWJyYXJ5KQ0KDQoNCg0KDQoNCg0KYGBge3Isd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGNhY2hlPUZBTFNFfQ0KDQojIVtUZXh0byBBbHRlcm5hdGl2b10oVVJMX2RlX2xhX2ltYWdlbikNCiMhWyoqQ3Vyc28gUjogQ2xhc2UgMSoqXShsb2dvYXVzdHJhbC5wbmcpe3dpZHRoPXdpZHRoPScxMDBweCcgaGVpZ2h0PXdpZHRoPScxMDBweCd9DQoNCmxpYnJhcnkocmVhZHhsKSAjbGVjdHVyYSBkZSBhcmNoaXZvcyBlbiBFeGNlbA0KbGlicmFyeShyZWFkcikgIyBwYXJhIGxlZXIgZGF0b3MgZGUgdGV4dG8gcmVjdGFuZ3VsYXJlcw0KbGlicmFyeShkcGx5cikgIyBtYW5lam8gZGUgZGF0b3MNCmxpYnJhcnkodGlkeXZlcnNlKSAjIG1hbmVqbyBkZSBkYXRvcw0KbGlicmFyeShEVCkNCmxpYnJhcnkoa2FibGVFeHRyYSkgIyBoYWNlciB0YWJsYXMgYm9uaXRhcw0KbGlicmFyeShsdWJyaWRhdGUpICMgbWFuZWpvIGRlIGZlY2hhcw0KbGlicmFyeShueWNmbGlnaHRzMTMpICMgYXJjaGl2byBkZSBkYXRvcyBkZSB2dWVsb3MNCmxpYnJhcnkoZ29vZ2xlc2hlZXRzNCkgIyBwYXJhIGxlZXIgZGVzZGUgZWwgR29vZ2xlIERyaXZlDQpsaWJyYXJ5KGZvcmVpZ24pDQpsaWJyYXJ5KHV0ZjgpDQoNCmBgYA0KDQoNCg0KDQoNCg0KDQpgYGB7cix3YXJuaW5nPUZBTFNFLGluY2x1ZGU9RkFMU0V9DQpTeXMuc2V0bG9jYWxlKCJMQ19BTEwiLCAiRVNfRVMuVVRGLTgiKSMgcGFyYSBsYXMgdGlsZGVzDQpgYGANCg0KIyBMb3MgQ2h1bmtzIA0KDQoNCkVuIGxvcyBDaHVua3Mgbm9zIHB1ZWRlIGludGVyZXNhciBjb25maWd1cmFyIHF1ZSBubyBub3MgZW52aWUgbWVuc2FqZXMgbyBxdWUgbm8gbXVlc3RyZSBlbCBjw7NkaWdvIG8gYmllbiBxdWUgbm8gbXVlc3RyZSBsYSBlamVjdWNpw7NuIGRlIHVuIGPDs2RpZ28uIEEgY29udGludWFjacOzbiBjw7NtbyBoYWNlcmxvOg0KDQoNCiAtICoqY2FjaGU9RkFMU0UqKiwgKiptZXNzYWdlPUZBTFNFKiosICoqd2FybmluZz1GQUxTRSoqLCBzaXJ2ZW4gcGFyYSBxdWUgbG9zIGNvbWFuZG9zIHF1ZSBtYW5kYW4gbWVuc2FqZXMgbm8gbG9zIGltcHJpbWFuIGVuIHBhbnRhbGxhLiBFc3RvIGVzIGltcG9ydGFudGUgc2kgcXVlcmVtb3MgcXVlIG51ZXN0cm9zIGxlY3RvcmVzIG5vIHNlcGFuIGxvIHF1ZSBlc3TDoSBjb3JyaWVuZG8gcG9yIGRldHLDoXMuDQoNCiAtICoqZXZhbCA9IEZBTFNFKiosIHNpcnZlIHBhcmEgcXVlIGxvcyBjw7NkaWdvcyBzZSBtdWVzdHJlbiwgcGVybyBxdWUgbm8gc2UgZWplY3V0ZW4uIEVzdG8gZXMgw7p0aWwgY3VhbmRvIGVzY3JpYmltb3MgdHV0b3JpYWxlcyBkZSBSIHBlcm8gbm8gcXVlcmVtb3MgcXVlIHNlIGVqZWN1dGUgbG8gcXVlIGhheSBkZW50cm8uDQoNCiAtICoqZWNobyA9IEZBTFNFKiosIHNpcnZlIHBhcmEgcXVlIGxvcyBjw7NkaWdvcyBzZSBlamVjdXRlbiBwZXJvIG5vIHNlIG11ZXN0cmVuLiBFc3RvIGVzIMO6dGlsIGN1YW5kbyBlc3RhbW9zIGVzY3JpYmllbmRvIHVuIGFydMOtY3VsbyB5IHF1ZXJlbW9zIHF1ZSBudWVzdHJvIGPDs2RpZ28gc2UgZWplY3V0ZSAocG9yIGVqZW1wbG8sIHBhcmEgY3JlYXIgdW5hIGdyw6FmaWNhIG8gdW4gbWFwYSkgcGVybyBubyBxdWVyZW1vcyBxdWUgbG9zIGxlY3RvcmVzIHZlYW4gbGFzIHRyaXBhcywgbyBlbCBjw7NkaWdvIHF1ZSBsbyBnZW5lcmEuDQoNCg0KDQojIyBMZWFtb3MgdW4gYXJjaGl2byB4bHN4IGRlc2RlIHVuYSBydXRhIHkgbG8gdmlzdWFsaXphbW9zDQoNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpiYXNlSU1DIDwtIHJlYWRfZXhjZWwoIi4uLy4uL0lNQ2luZmFudGlsLnhsc3giKQ0KDQoNCmJhc2VJTUMNCmBgYA0KDQoNCg0KIyMgY8OzbW8gcG9kZW1vcyBhY2NlZGVyIGEgdW5hIGNvbHVtbmEgKHZhcmlhYmxlKSAtIG1vZG8gY2zDoXNpY28NCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpiYXNlSU1DWyw0XSAjIGFjY2VkZW1vcyBhIGxhIGN1YXJ0YSBjb2x1bW5hDQoNCmJhc2VJTUMkUEVTTyAjIGFjY2VkZW1vcyBhIGxhIG1pc21hIGNvbHVtbmEgcGVybyBwb3Igc3Ugbm9tYnJlDQoNCmBgYA0KIyMgY8OzbW8gcG9kZW1vcyBhY2NlZGVyIGEgdW5hIGZpbGEgKHJlZ2lzdHJvKS0gbW9kbyBjbMOhc2ljbw0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KYmFzZUlNQ1szLF0NCmJhc2VJTUNbYmFzZUlNQyRQQUNJRU5URT09IjMiLF0NCmBgYA0KDQojIyBjw7NtbyBwb2RlbW9zIGFjY2VkZXIgYSB1biBkYXRvIChmaWxhIHkgY29sdW1uYSBlc3BlY2lmaWNhcykNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCmJhc2VJTUNbMywyXQ0KYmFzZUlNQ1tiYXNlSU1DJFBBQ0lFTlRFPT0iMyIsMl0NCmBgYA0KDQoNClsqKkN1w6FsIGVzIGxhIGRpZmVyZW5jaWEgZW50cmUgYW1iYXMgc2FsaWRhcz8qKl17c3R5bGU9ImNvbG9yOnJlZCJ9DQoNCiMgTGVlbW9zIGRhdG9zIGRlc2RlIHVuYSB1cmwNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCnVybC5kYXQgPC0gImh0dHA6Ly9iaXQubHkvRGF0YWJhc2UtRXN0dWRpYW50ZXMiICAgICMgTGEgdXJsIGRlc2RlIGRyaXZlDQplc3R1ZGlhbnRlcyA8LSByZWFkLmRlbGltKHVybC5kYXQpIA0KZXN0dWRpYW50ZXMNCmBgYA0KDQoNCg0KDQoNCiMgQWhvcmEgdW5hIGZvcm1hIG3DoXMgbW9kZXJuYTogTGEgQmlibGlvdGVjYSBkcGx5cg0KDQoNCg0KKipFbCBwYXF1ZXRlIGRwbHlyIHByb3BvcmNpb25hIHVuYSBmb3JtYSBiYXN0YW50ZSDDoWdpbCBkZSBtYW5lamFyIGxvcyBmaWNoZXJvcyBkZSBkYXRvcyBkZSBSLiBBZGVtw6FzLCBlbCBjw7NkaWdvIGVzY3JpdG8gdXNhbmRvIGVzdGUgcGFxdWV0ZSAoZXNwZWNpYWxtZW50ZSB1c2FuZG8gbGEgc2ludGF4aXMgZW4gY2FkZW5hIHF1ZSB2ZXJlbW9zIG3DoXMgYWRlbGFudGUpIGVzIG11Y2hvIG3DoXMgbGVnaWJsZSB5IGbDoWNpbCBkZSBlbnRlbmRlcioqLiANCg0KDQoqKkVsIHBhcXVldGUgaW5jbHV5ZSB1biBjb25qdW50byBkZSBjb21hbmRvcyBxdWUgY29pbmNpZGVuIGNvbiBsYXMgYWNjaW9uZXMgbcOhcyBjb211bmVzIHF1ZSBzZSByZWFsaXphbiBzb2JyZSB1biBjb25qdW50byBkZSBkYXRvcyAoc2VsZWNjaW9uYXIgZmlsYXMgZmlsdGVyLCBzZWxlY2Npb25hciBjb2x1bW5hcyBzZWxlY3QsIG9yZGVuYXIgYXJyYW5nZSwgYcOxYWRpciBudWV2YXMgdmFyaWFibGVzIG11dGF0ZSwgcmVzdW1pciBtZWRpYW50ZSBhbGd1bmEgbWVkaWRhIG51bcOpcmljYSBzdW1tYXJpc2UpLiBMbyBxdWUgaGFjZSBxdWUgbGEgc2ludGF4aXMgc2VhIGVzcGVjaWFsbWVudGUgY2xhcmEgZXMgbGEgY29ycmVzcG9uZGVuY2lhIHRhbiBuw610aWRhIGVudHJlIGVsIGNvbWFuZG8geSBsYSBhY2Npw7NuLiBQYXJhIGxsZXZhciBhIGNhYm8gZXN0YXMgYWNjaW9uZXMgZGViZW1vcyB0ZW5lciBlbiBjdWVudGEgYWxndW5hcyBjYXJhY3RlcsOtc3RpY2FzIGNvbXVuZXM6KioNCg0KIC0gRWwgcHJpbWVyIGFyZ3VtZW50byBzaWVtcHJlIGVzIHVuIGRhdGEuZnJhbWUNCiAtIEVsIHJlc3RvIGRlIGFyZ3VtZW50b3MgaW5kaWNhbiBsbyBxdWUgcXVlcmVtb3MgaGFjZXIgY29uIGVsIGRhdGEuZnJhbWUuDQogLSBFbCByZXN1bHRhZG8gc2llbXByZSB0aWVuZSB0YW1iacOpbiBsYSBlc3RydWN0dXJhIGRlIGRhdGEuZnJhbWUNCg0KDQoNCg0KDQojIyBTZWxlY2Npb25hciBmaWxhczogZmlsdGVyKCkNCiBFc3RhIGFjY2nDs24gY29uc2lzdGUgZW4gc2VsZWNjaW9uYXIgbGFzIG9ic2VydmFjaW9uZXMgKGZpbGFzKSBxdWUgY3VtcGxlbiBsYXMgY29uZGljaW9uZXMgcXVlIG5vcyBpbnRlcmVzYW4uKioNCiANCipUcmVzIGVqZW1wbG9zKg0KDQogLSBlbCBwcmltZXIgY29tYW5kbyBzZWxlY2Npb25hIHRvZG9zIGxvcyBlc3R1ZGlhbnRlcyBjYXRlZ29yaXphZG9zIGNvbW8gYWx0b3MuDQogLSBlbCBzZWd1bmRvIHNlbGVjY2lvbmEgbG9zIGVzdHVkaWFudGVzIGNhdGVnb3JpemFkb3MgY29tbyBhbHRvcyBvIG1lZGlvcy4NCiAtIGVsIHRlcmNlcm8gc2VsZWNjaW9uYSBsb3MgZXN0dWRpYW50ZXMgYWx0b3MgbWVub3JlcyBhIDE3IGHDsW9zLg0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KDQpmaWx0ZXIoZXN0dWRpYW50ZXMsIEVzdGF0dXJhPT0nQWx0YScpDQpmaWx0ZXIoZXN0dWRpYW50ZXMsIEVzdGF0dXJhPT0nQWx0YScgfCBFc3RhdHVyYT09J01lZGlhJykNCmZpbHRlcihlc3R1ZGlhbnRlcywgRXN0YXR1cmE9PSdBbHRhJywgRWRhZCA8IDE3KQ0KDQoNCg0KYGBgDQoNCiMjIFNlbGVjY2lvbmFyIGNvbHVtbmFzOiBzZWxlY3QoKQ0KIEVzdGEgYWNjacOzbiBjb25zaXN0ZSBlbiBlbGVnaXIgdW4gc3ViY29uanVudG8gZGUgbGFzIHZhcmlhYmxlcyAoY29sdW1uYXMpIGRlbCBmaWNoZXJvLiBQb3IgZWplbXBsbyBwb2RlbW9zIHNlbGVjY2lvbmFyIGRlIGxhIGJhc2UgZGUgZXN0dWRpYW50ZXMgbGFzIHZhcmlhYmxlcyBFc3RhdHVyYSB5IGVsIENvbGVnaW8uDQogDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0Kc2VsZWN0KGVzdHVkaWFudGVzLCBFc3RhdHVyYSwgQ29sZWdpbykNCmBgYA0KDQoNCg0KDQojIyBEb3MgZWplbXBsb3MNCiAtIEVzIHBvc2libGUgc2VsZWNjaW9uYXIgdW4gcmFuZ28gZGUgdmFyaWFibGVzIHV0aWxpemFuZG8gIjoiIA0KIC0gbyBlbGVnaXIgdG9kYXMgbGFzIHZhcmlhYmxlcyBtZW5vcyBhbGd1bmFzLg0KIC0gRWwgcHJpbWVyIGVqZW1wbG8gc2VsZWNjaW9uYSB0b2RhcyBsYXMgdmFyaWFibGVzIGVudHJlIENvbGVnaW8geSBQMw0KIC0gRWwgc2VndW5kbyBzZWxlY2Npb25hIHRvZGFzIG1lbm9zIFNleG8NCiAtIEVsIHRlcmNlcm8gZXhjbHV5ZSBsYXMgdmFyaWFibGVzIGRlc2RlIEdhc3RvcyBoYXN0YSBBR1BFUTIgaW5jbHVzaXZlDQogDQogDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0Kc2VsZWN0KGVzdHVkaWFudGVzLCBDb2xlZ2lvOlAzKQ0Kc2VsZWN0KGVzdHVkaWFudGVzLCAtU2V4bykNCnNlbGVjdChlc3R1ZGlhbnRlcywgLShHYXN0b3M6QUdQRVEyKSkNCmBgYA0KDQoNCg0KIE90cmEgcG9zaWJpbGlkYWQgZXMgc2VsZWNjaW9uYXIgbGFzIHZhcmlhYmxlcyBjdXlvIG5vbWJyZSANCiBjb250ZW5nYSBjaWVydG9zIHTDqXJtaW5vczoNCiANCiAtIEVsIHByaW1lciBlamVtcGxvIHNlbGVjY2lvbmEgbGFzIHZhcmlhYmxlcyBxdWUgZW4gc3Ugbm9tYnJlIGNvbnRpZW5lbiBsYSBwYWxhYnJhIFNleG8uDQogLSBFbCBzZWd1bmRvIGVqZW1wbG8gYSBsYXMgbWlzbWFzIHZhcmlhYmxlcyBsYXMgZXhjbHV5ZS4NCiANCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpzZWxlY3QoZXN0dWRpYW50ZXMsIGNvbnRhaW5zKCdTZXhvJykpIA0Kc2VsZWN0KGVzdHVkaWFudGVzLCAtY29udGFpbnMoJ1NleG8nKSkgDQpgYGANCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpzZWxlY3QoZXN0dWRpYW50ZXMsc3RhcnRzX3dpdGgoJ3AnKSkNCnNlbGVjdChlc3R1ZGlhbnRlcyxlbmRzX3dpdGgoJ3MnKSkNCmBgYA0KDQoNCg0KIyBPcmRlbmFyOiBhcnJhbmdlKCkNCiMjIE9yZGVuYSBsYXMgZmlsYXMgZGUgbWVub3IgYSBtYXlvciB2YWxvciBkZSBsYSB2YXJpYWJsZSBlbGVnaWRhLg0KDQoqKlNpIGVzY3JpYmltb3MgdW4gc2lnbm8gbWVub3MsIG9yZGVuYSBkZSBtYXlvciBhIG1lbm9yLioqIA0KDQpQb3IgZWplbXBsbyBwYXJhIG9yZGVuYXIgZGUgbGEgYmFzZSBkZSBlc3R1ZGlhbnRlcyBlbiBmdW5jacOzbiBkZSBsYSBFZGFkOg0KDQogLSBFbCBwcmltZXIgZWplbXBsbyBvcmRlbmEgbGEgYmFzZSBkZSBlc3R1ZGlhbnRlcyBlbiBmdW5jacOzbiBkZSBsYSBFZGFkIGRlIG1lbm9yIGEgbWF5b3INCiAtIEVsIHNlZ3VuZG8gZWplbXBsbyBsbyBoYWNlIGRlIG1heW9yIGEgbWVub3INCiAtIEVsIHRlcmNlciBlamVtcGxvIG9yZGVuYSBwcmltZXJvIHBvciBFZGFkICB5IHNlZ3VuZG8gcG9yIGxhIG5vdGEgZGUgbGEgZXZhbHVhY2nDs24gRmluYWwNCiAtIEVsIGN1YXJ0byBlamVtcGxvIGxvIG9yZGVuYSBlbiBmb3JtYSBjcmVjaWVudGUgZGUgZWRhZCAgeSBkZWNyZWNpZW50ZSBkZSBub3RhIGRlIGV2YWx1YWNpw7NuIGZpbmFsDQoNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQogICANCmFycmFuZ2UoZXN0dWRpYW50ZXMsIEVkYWQpIA0KYXJyYW5nZShlc3R1ZGlhbnRlcywgLUVkYWQpDQphcnJhbmdlKGVzdHVkaWFudGVzLCBFZGFkLCBGaW5hbCkNCmFycmFuZ2UoZXN0dWRpYW50ZXMsIEVkYWQsIC1GaW5hbCkNCmBgYA0KDQojIFNpbnRheGlzIGVuIGNhZGVuYQ0KDQpFbCBwYXF1ZXRlIGluY29ycG9yYSB1bmEgc2ludGF4aXMgZW5jYWRlbmFkYSBxdWUgcGVybWl0ZSBlc2NyaWJpciBsYXMgYWNjaW9uZXMNCmVuIHVuIG9yZGVuIG5hdHVyYWwsIGVuIG9wb3NpY2nDs24gYSBsYSBmb3JtYSBhbmlkYWRhIGVuIGxhIHF1ZSBsbyBoYXLDrWFtb3MgDQpub3JtYWxtZW50ZS4gDQoNCioqUHJpbWVybyBzZSBlc2NyaWJlIGVsIG5vbWJyZSBkZWwgZmljaGVybyB5IGx1ZWdvIGxhcyBhY2Npb25lcyoqDQoNCkVuIGVsIG9yZGVuIGVuIHF1ZSBzZSByZWFsaXphbiBzZXBhcmFkYXMgcG9yIGVsIG9wZXJhZG9yICU+JQ0KKHF1ZSBwb2Ryw61hbW9zIGxlZXIgY29tbyBlbnRvbmNlcyApLiBFc3RlIG9wZXJhZG9yIHNlIGRlbm9taW5hICJwaXBlIiB5IHNlIHRyYWR1Y2UgY29tbyBjYcOxby4gDQoqUG9yIGVqZW1wbG8sIHNpIHF1ZXJlbW9zIHNlbGVjY2lvbmFyIGxhcyB2YXJpYWJsZXMgcXVlIGNvbnRpZW5lbiANCmxhcyBtZWRpZGFzIGRlbCBww6l0YWxvLCBzZWxlY2Npb25hciBsb3MgbGlyaW9zIHBhcmEgbG9zIHF1ZSBsYSBsb25naXR1ZCBkZWwgcMOpdGFsbw0KZXMgbWF5b3IgcXVlIDQgbW0geSBvcmRlbmFybG9zIGRlIG1lbm9yIGEgbWF5b3IgbG9uZ2l0dWQgZGVsIHDDqXRhbG8sIA0KcG9kZW1vcyBlc2NyaWJpcjoqDQoNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0gDQoNCg0KZXN0dWRpYW50ZXMgJT4lDQogIHNlbGVjdChjb250YWlucygnUCcpKSU+JQ0KICBzZWxlY3QoLWNvbnRhaW5zKCdBJykpICU+JQ0KICBmaWx0ZXIoUDEgPiA0KSU+JQ0KICBhcnJhbmdlKFAyKQ0KYGBgDQoNCg0KDQoNCg0KIyBQYXJhIHNlbGVjY2lvbmFyIGxhcyB2YXJpYWJsZXMgbnVtw6lyaWNhcyBzb2xhbWVudGUNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCmVzdHVkaWFudGVzICU+JSANCiAgc2VsZWN0X2lmKC4sIGlzLm51bWVyaWMpDQoNCmBgYA0KIyBQYXJhIHNlbGVjY2lvbmFyIGxhcyB2YXJpYWJsZXMgcXVlIHNvbiBkZSB0aXBvIGNhcmFjdGVyIHNvbGFtZW50ZQ0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KZXN0dWRpYW50ZXMgJT4lIA0KICBzZWxlY3RfaWYoLiwgaXMuY2hhcmFjdGVyKQ0KYGBgDQojIyBQb2RlbW9zIHNlbGVjY2lvbmFyIGFsZ3Vub3MgcmVnaXN0cm9zIGNvbiBzbGljZSgpDQoNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpiYXNlSU1DICU+JSANCiAgc2xpY2UoMSwgMTE6MTMsIDIxKQ0KDQojLSBOb3MgcXVlZGFtb3MgYWNhDQpgYGANCg0KDQojICoqRWplcmNpY2lvIDEqKg0KDQpFeHBsaWNhIGNvbiB0dXMgcGFsYWJyYXMgbGEgc2VjdWVuY2lhIGFudGVyaW9yLg0KDQpSZXNwdWVzdGE6DQpzbGljZSgxLCAxMToxMywgMjEpOiBzZWxlY2Npb25hIGxhcyBmaWxhcyAxLCBkZWwgMTEgYWwgMTMgeSBsYSAyMS4NCg0KIyAqKkVqZXJjaWNpbyAyICoqDQoNCkNvbiBsYSBiYXNlIGRlIElNQyBxdWUgdmltb3MgYWwgcHJpbmNpcGlvLg0KDQphKSBTZWxlY2Npb25hciBsYXMgdmFyaWFibGVzIFBlc28sIFRhbGxhIGUgSU1DLg0KDQpgYGB7cn0NCnNlbGVjdChiYXNlSU1DLCBQRVNPLCBUQUxMQSwgSU1DKQ0KYGBgDQoNCg0KYikgU2VsZWNjaW9uYXIgbG9zIHJlZ2lzdHJvcyBkZSBsYXMgbXVqZXJlcy4NCg0KYGBge3J9DQpmaWx0ZXIoYmFzZUlNQywgU0VYTz09J0YnKQ0KYGBgDQoNCg0KYykgRGUgbG9zIHJlZ2lzdHJvcyBkZSBsYXMgbXVqZXJlcywgc2VsZWNjaW9uYXIgbGFzIHZhcmlhYmxlcyBFZGFkIHkgQ2F0UGVzby4NCg0KYGBge3J9DQpiYXNlSU1DICU+JQ0KICBmaWx0ZXIoU0VYTyA9PSAnRicpJT4lDQogIHNlbGVjdChTRVhPLEVEQUQsQ2F0UGVzbykNCiAgDQpgYGANCg0KDQpkKSBEZSBsb3MgcmVnaXN0cm9zIGRlIGxhcyBtdWplcmVzLCBzZWxlY2Npb25hciBsYXMgdmFyaWFibGVzIEVkYWQgeSBDYXRwZXNvIHkgbHVlZ28gb3JkZW5hcmxvcyBlbiBmb3JtYSBjcmVjaWVudGUgcG9yIEVkYWQuDQoNCmBgYHtyfQ0KYmFzZUlNQyAlPiUgDQogIGZpbHRlcihTRVhPID09ICdGJykgJT4lIA0KICBzZWxlY3QoU0VYTyxFREFELENhdFBlc28pICU+JSANCiAgYXJyYW5nZShFREFEKQ0KYGBgDQoNCg0KZSkgT3JkZW5hciBsYSBiYXNlIGVuIGZvcm1hIGRlY3JlY2llbnRlIHBvciBJTUMuDQoNCmBgYHtyfQ0KYmFzZUlNQyAlPiUgDQogIGFycmFuZ2UoLUlNQykNCmBgYA0KDQoNCmYpIERlIGxhIGJhc2Ugb3JkZW5hZGEgZW4gZm9ybWEgZGVjcmVjaWVudGUgcG9yIElNQywgc2VsZWNjaW9uYXIgbG9zIHF1ZSB0aWVuZW4gc29icmVwZXNvIHkgcXVlZGFyc2UgY29uIGxhcyBjb2x1bW5hcyBkZSBFZGFkLCBUYWxsYSB5IFBlc28uDQoNCmBgYHtyfQ0KYmFzZUlNQyAlPiUgDQogIGFycmFuZ2UoLUlNQykgJT4lIA0KICBmaWx0ZXIoSU1DID4gMzApICU+JSANCiAgc2VsZWN0KElNQywgRURBRCwgVEFMTEEsIFBFU08pDQpgYGANCg0KDQpnKSBTZWxlY2Npb25hciBsYXMgdmFyaWFibGVzIFRhbGxhLCBJTUMgeSBDQyB5IGZpbHRyYXIgbG9zIHJlZ2lzdHJvcyAxLCA1LCA2LCA3IHkgMTUuIEd1YXJkYXIgZXN0byBlbiB1bmEgYmFzZSBxdWUgc2UgbGxhbWUgYmFzZUlNQ19hdXggeSBtb3N0cmFyIGPDs21vIGVzIGxhIG51ZXZhIGJhc2UuDQoNCg0KYGBge3J9DQpiYXNlSU1DX2F1eCA8LSBiYXNlSU1DICU+JSANCiAgc2VsZWN0KFRBTExBLCBJTUMsIENDKSAlPiUNCiAgc2xpY2UoMSw1OjYsNSkNCg0KYmFzZUlNQ19hdXgNCmBgYA0KDQoNCg0KIyBBw7FhZGlyIG51ZXZhcyB2YXJpYWJsZXM6IG11dGF0ZSgpDQoNClNlZ3VpbW9zIGNvbiBsYXMgYWNjaW9uZXMgYsOhc2ljYXMgaW1wbGVtZW50YWRhcyBlbiBsYSBiaWJsaW90ZWNhIGRwbHlyLg0KDQoqKlZlYW1vcyBjb21vIGNyZWFyIG51ZXZhcyB2YXJpYWJsZXMgcXVlIHNvbiBmdW5jacOzbiBkZSBsYXMgeWEgZXhpc3RlbnRlcy4qKiANCg0KRW4gZXN0ZSBlamVtcGxvIGNyZWFtb3MgdW5hIHZhcmlhYmxlIHF1ZSBjb3JyZXNwb25kZSBhbCBjb2NpZW50ZSBlbnRyZSBsYSBUYWxsYSB5IGxhIENDIChxdWUgcG9kcsOtYSBjb3JyZXNwb25kZXIgYSBhbGfDum4gYXNwZWN0byBkZSBsYSBmb3JtYSBkZSBsYSBwZXJzb25hIGRlIGludGVyw6lzIHBhcmEgc3Ugcmllc2dvIGNhcmRpb3Zhc2N1bGFyKSBlbiBsYSBiYXNlSU1DOg0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KYmFzZUlNQzwtYmFzZUlNQyAlPiUNCiAgbXV0YXRlKGZvcm1hID0gVEFMTEEvQ0MpDQpiYXNlSU1DDQpgYGANCg0KW09ic2VydmVtb3MgcXVlIGxhIG51ZXZhIHZhcmlhYmxlIGZvcm1hIGFwYXJlY2UgZW4gbGEgw7psdGltYSBjb2x1bW5hLl17c3R5bGU9ImNvbG9yOmRhcmtncmVlbiJ9DQoNCg0KDQpbUG9kcsOtYW1vcyByZWRvbmRlYXIgbG9zIHZhbG9yZXMgZGUgZXN0YSBudWV2YSB2YXJpYWJsZSwgcG9yIGVqZW1wbG8gY29uIHRyZXMgY2lmcmFzIGRlY2ltYWxlcy5de3N0eWxlPSJjb2xvcjpkYXJrZ3JlZW4ifQ0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KYmFzZUlNQzwtYmFzZUlNQyAlPiUNCiAgbXV0YXRlKGZvcm1hID0gcm91bmQoVEFMTEEvQ0MsMykpDQpiYXNlSU1DDQpgYGANCg0KDQojIFJlc3VtaXIgKHN1YmNvbmp1bnRvcyBkZSkgdmFyaWFibGVzOiBncm91cF9ieSgpICsgc3VtbWFyaXNlKCkNCiMjIFVzYW1vcyBzdW1tYXJpc2UoKSBwYXJhIGFwbGljYXIgY29tYW5kb3MgYSB2YXJpYWJsZXMuIA0KDQoqKk5vcm1hbG1lbnRlIHNlIHVzYSBlbiBjb21iaW5hY2nDs24gY29uIGdyb3VwX2J5KCkgZGUgbWFuZXJhIHF1ZSBzZSBjYWxjdWxlbiANCiBlc3RhZMOtc3RpY29zIHBhcmEgc3ViZ3J1cG9zIGRlIG9ic2VydmFjaW9uZXMuICoqDQogDQogRW4gZWwgc2lndWllbnRlIGVqZW1wbG8gc2UgY2FsY3VsYQ0KIGxhIG1lZGlhIGRlbCBJTUMgcGFyYSBjYWRhIGNhdGVnb3LDrWEgZGUgUGVzbzogDQogDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KcmVzdW1lbjE8LWJhc2VJTUMgJT4lDQogICAgZ3JvdXBfYnkoQ2F0UGVzbykgJT4lIHN1bW1hcmlzZShNZWRpYV9mb3JtYT1tZWFuKGZvcm1hKSxuPW4oKSxzdGRldj1zZChmb3JtYSkpICU+JSBtdXRhdGVfaWYoaXMubnVtZXJpYywgfnJvdW5kKC4sIDQpKQ0KcmVzdW1lbjENCg0KYGBgDQoNCg0KIyBQYXJhIGV4dHJhZXIgYWxlYXRvcmlhbWVudGUgYWxndW5hcyBvYnNlcnZhY2lvbmVzIHNhbXBsZV9uKCkNCiAgDQoqRXh0cmFlIDQgb2JzLiBzaW4gcmVlbXBsYXpvIGRlIGxhIGJhc2UgZGUgZXN0dWRpYW50ZXMqDQoNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQojIFBvZGVtb3MgZmlqYXIgdW5hIHNlbWlsbGEgcXVlIG5vcyBoYWNlIHJlcGV0aWJsZSBhbCBleHBlcmltZW50bw0Kc2V0LnNlZWQoMjcpDQplc3R1ZGlhbnRlcyAlPiUgc2FtcGxlX24oNCkNCmBgYA0KIyBFeHRyYWUgdW4gMjUlIGRlIG9icyBjb24vc2luIHJlZW1wbGF6YW1pZW50bw0KYGBge3IsY29sbGFwc2U9VFJVRX0NCnNldC5zZWVkKDEyMykNCmVzdHVkaWFudGVzICU+JSBzYW1wbGVfZnJhYygwLjI1LCByZXA9RkFMU0UpICU+JSBhcnJhbmdlKE9ic2VydmFjaW9uKSANCiMgZW4gZXN0ZSBjYXNvIHBvZGVtb3Mgb3B0YXIgcG9yIGNvbiBvIHNpbiByZXBvc2ljacOzbiBlbiBlbCBtdWVzdHJlbw0KYGBgDQojIEhheSBkaXN0aW5hcyBwb3NpYmlsaWRhZGVzIHF1ZSBub3MgcGVybWl0ZW4gIHZpc3VhbGl6YXIgbGFzIHZhcmlhYmxlcyBzdSB0aXBvIHkgYWxndW5vcyB2YWxvcmVzLCB2ZWFtb3Mgc2ltaWxpdHVkZXMgeSBkaWZlcmVuY2lhcw0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KIGdsaW1wc2UoYmFzZUlNQykNCmBgYA0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0Kc3VtbWFyeShiYXNlSU1DKQ0KYGBgDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0Kc3RyKGJhc2VJTUMpDQpgYGANCg0KDQogT3Ryb3MgcmVzw7ptZW5lcyBjb21vIGRlc3bDrW8gc3RhbmRhcmQgeSBjYW50aWRhZCBkZSByZWdpc3Ryb3MNCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KYGBge3IsY29sbGFwc2U9VFJVRX0NCmJhc2VJTUMgJT4lIA0KICBzZWxlY3QoVEFMTEEsU0VYTykgJT4lIA0KICBncm91cF9ieShTRVhPKSAlPiUgDQogIHN1bW1hcmlzZShUb3RhbF9SZWdpc3Ryb3M9bigpLCANCiAgICBtZWRpYV90YWxsYT1tZWFuKFRBTExBKSwgDQogICAgc2RfdGFsbGE9c2QoVEFMTEEpKSAlPiUgDQogIGFycmFuZ2UoLW1lZGlhX3RhbGxhKQ0KYGBgDQoNCg0KDQpbUGFyYSBxdWUgbXVlc3RyZSBhbGd1bm9zIHJlZ2lzdHJvcyBkZSBsb3MgcHJpbWVyb3MgdXNhbW9zIGhlYWQoKV17c3R5bGU9ImNvbG9yOmJsdWUifQ0KW1BhcmEgcXVlIG11ZXN0cmUgYWxndW5vcyByZWdpc3Ryb3MgZGUgbG9zIMO6bHRpbW9zIHVzYW1vcyB0YWlsKCkuXXtzdHlsZT0iY29sb3I6Ymx1ZSJ9DQoNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQplc3R1ZGlhbnRlcyAlPiUgYXJyYW5nZShkZXNjKEZpbmFsKSkgJT4lIGhlYWQoOCkNCmVzdHVkaWFudGVzICU+JSBhcnJhbmdlKEZpbmFsKSAlPiUgdGFpbCg4KQ0KYGBgDQoNCiMgUGFyYSBhZ3JlZ2FyIHVuYSBudWV2YSBmaWxhIGEgbGEgYmFzZSBkZSBkYXRvcyBwb2RlbW9zIHV0aWxpemFyIGFkZF9yb3coKToNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCmJhc2VJTUMxIDwtIGJhc2VJTUMgJT4lIGFkZF9yb3coUEFDSUVOVEU9IDE1MSwgRURBRCA9IDEyLCBTRVhPPSJNIiwgIFRBTExBPTEuMyxJTUM9MTYuNyxDQz03NSkNCmJhc2VJTUMxDQpgYGANClsqKk9ic2VydmVuIHF1w6kgb2N1cnJpw7MgY29uIGxhcyB2YXJpYWJsZXMgcXVlIG5vIGNhcmdhbW9zISEqKl17c3R5bGU9ImNvbG9yOmRhcmtibHVlIn0NCg0KDQpPdHJhIGNhcmFjdGVyw61zdGljYSBpbXBvcnRhbnRlIGVzIGVsIGNvbnRlbywgcG9kcsOtYW1vcyBlc3RhciBpbnRlcmVzYWRvcywgZGFkbyB1biBjb25qdW50byBkZSBjbGFzZXMgY3VhbCBlcyBzdSBmcmVjdWVuY2lhIGFic29sdXRhIGRlIGNhZGEgY2F0ZWdvcsOtYSwgcGFyYSBlc3RvIHV0aWxpemFyZW1vcyBjb3VudCgpIGVsIGN1YWwgZ2VuZXJhIHVuYSB2YXJpYWJsZSBxdWUgY29udGllbmUgZGljaGFzIGZyZWN1ZW5jaWFzLg0KDQoNCkFob3JhIGVsaW1pbmFtb3MgbGEvcyBmaWxhL3MgcXVlIHRlbmdhbiBhbGfDum4gcmVnaXN0cm8gZmFsdGFudGUNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpiYXNlSU1DMSAlPiUgbmEub21pdCgpDQpgYGANCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpiYXNlSU1DICU+JSBjb3VudChDYXRQZXNvKQ0KDQoNCiN0YWJsZShiYXNlSU1DJENhdFBlc28pDQpgYGANCg0KYGBge3J9DQpiYXNlSU1DJT4lc3VtbWFyaXplKG5fZGlzdGluY3QoQ2F0UGVzbykpDQoNCiNsZW5ndGgodW5pcXVlKGJhc2VJTUMkQ2F0UGVzbykpDQpgYGANCg0KDQojIFBvZGVtb3MgdXRpbGl6YXIgZWwgY29uZGljaW9uYWwgaWZlbHNlKCkgcGFyYSBjcmVhciBudWV2YXMgIHZhcmlhYmxlcyBzZWfDum4gY2llcnRhcyBjb25kaWNpb25lczoNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCmJhc2VJTUMyPC1iYXNlSU1DICU+JSBtdXRhdGUoY2F0ZWdvcsOtYSA9IGlmZWxzZShFREFEID4gMTAsICJNYXlvciIsICJNZW5vciIpKQ0KYmFzZUlNQzINCg0KYGBgDQoNCg0KIyMgUmVub21icmFuZG8gdmFyaWFibGVzDQoNClRhbWJpw6luIHBvZGVtb3MgY2FtYmlhciBlbCBub21icmUgYSB1bmEgdmFyaWFibGUuDQoNCg0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KZXN0dWRpYW50ZXMgJT4lIA0KICByZW5hbWUoR2FzdG9fdG90YWwgPSBHYXN0b3MpDQoNCg0KIy0gVGFtYmllbiB0ZW5lbW9zIGVzdGFzIG9wY2lvbmVzDQojbmFtZXMoZGYpW25hbWVzKGRmKSA9PSAnb2xkLnZhci5uYW1lJ10gPC0gJ25ldy52YXIubmFtZScNCiNjb2xuYW1lcyhkZilbcG9zaXRpb25dIDwtICJuZXduYW1lMiINCg0KYGBgDQoNCg0KIyBDdWFuZG8gcXVpZXJvIGNhbWJpYXIgZWwgbm9tYnJlIGRlIHRvZGFzIGxhcyBjb2x1bW5hcyBzZXROYW1lcygpDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KYmFzZUlNQzM8LWJhc2VJTUMgJT4lIA0KICBzZXROYW1lcyhjKCJQYWNpZW50ZSIsICJFZGFkIiwgIlNleG8iLCJQZXNvIiwiVGFsbGEiLCJCTUkiLCJCTUlfcGVyYyIsIlBDIiwiQ2F0X1Blc28iLCJGb3JtYSIpKQ0KYmFzZUlNQzMNCmBgYA0KDQojICoqRWplcmNpY2lvIDMqKg0KDQpDb24gbG9zIGRhdG9zIGRlIEFkbWlzacOzbiwgY3V5YXMgdmFyaWFibGVzIGluZGljYW4gc2kgZWwgZXN0dWRpYW50ZSBmdWUgYWRtaXRpZG8gKGNhdGVnb3LDrWEgMSkgZW4gdW5hIGNhcnJlcmEgZGUgcG9zZ3JhZG8sIGVsIHB1bnRhamUgZGVsIGVzdHVkaWFudGVzIGVuICBHUkUgKGdyYWR1YXRlIHJlY29yZCBleGFtIHNjb3Jlcy1wdW50YWplcyBkZSBleMOhbWVuZXMgZGUgcmVnaXN0cm8gZGUgcG9zZ3JhZG8pIHkgR1BBIChncmFkZSBwb2ludCBhdmVyYWdlLSBwcm9tZWRpbyBkZSBjYWxpZmljYWNpb25lcyBkZSBsYSBjYXJyZXJhIGRlIGdyYWRvKSB5IGVsIHJhbmsocmFuayBvZiB0aGUgdW5kZXJncmFkdWF0ZSBzY2hvb2wtIHJhbmdvIGRlIGxhIGVzY3VlbGEgZGUgcHJlZ3JhZG8pLg0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsaW5jbHVkZT1GQUxTRSxjb2xsYXBzZT1UUlVFfQ0KdXJsID0gJ2h0dHA6Ly9zdGF0cy5pZHJlLnVjbGEuZWR1L3N0YXQvc3RhdGEvZGFlL2JpbmFyeS5kdGEnDQp0bXBmaWxlIDwtIHRlbXBmaWxlKCkNCmRvd25sb2FkLmZpbGUodXJsLCB0bXBmaWxlKQ0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxjYWNoZT1GQUxTRSxjb2xsYXBzZT1UUlVFfQ0KYWRtaXNpb24gPC0gcmVhZC5kdGEodXJsKSAgDQpoZWFkKGFkbWlzaW9uLDgpDQphZG1pc2lvbg0KYGBgDQoNCmEpIENyZWFyIHVuYSBudWV2YSB2YXJpYWJsZSBxdWUgcHJvbWVkaWUgbG9zIHZhbG9yZXMgZGUgZ3JlIHkgZ3BhLg0KYikgQWdydXBhciBwb3IgcmFuayB5IHByb21lZGlhciBncmUgeSBncGEgcGFyYSBjYWRhIHJhbmsuDQpjKSBFeHRyYWVyIHVuYSBtdWVzdHJhIGRlIDEwMCByZWdpc3Ryb3Mgc2luIHJlcG9zaWNpw7NuIGRlIGRvcyBtYW5lcmFzIGRpc3RpbnRhcy4NCmQpIFJlc3VtaXIgbGFzIHZhcmlhYmxlcyBkZSBsYSBiYXNlDQplKSBBZ3JlZ2FyIHVuYSBmaWxhIHF1ZSByZXN1bHRlIG11eSBkaWZlcmVudGUgYSBsYXMgb3RyYXMgeSBubyBjb2xvY2FyIHJhbmsuDQpmKSBFbGltaW5hciBsb3MgcmVnaXN0cm9zIHF1ZSB0ZW5nYW4gYWxnw7puIHZhbG9yIGZhbHRhbnRlLg0KZykgQ29udGFyIGN1w6FudG9zIGZ1ZXJvbiBhZG1pdGlkb3MgeSBjdWFudG9zIG5vLg0KaCkgQ29udGFyIGN1w6FudG9zIGhheSBkZSBjYWRhIHJhbmdvIGRlIGVzY3VlbGEuDQppKSBDYW1iaWFyIGVsIG5vbWJyZSBkZSB1bmEgbGFzIHZhcmlhYmxlcyAoc2VhbiBjcmVhdGl2b3MhKS4NCmopIENhbWJpYXIgZWwgbm9tYnJlIGRlIHRvZGFzIGxhcyB2YXJpYWJsZXMgKHDDs25nYW5sZSBodW1vciEpLg0KDQoNCg0KDQojIENhbWJpYXIgbml2ZWxlcyBkZSB1biBmYWN0b3INCg0KRW4gbGEgYmFzZSBkZSBlc3R1ZGlhbnRlcyBxdWVyZW1vcyByZWNvZGlmaWNhciBsYSB2YXJpYWJsZSBGdW1hDQoNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpkZiA8LSBlc3R1ZGlhbnRlc1sxOjQwLDE6MTBdDQpkZjwtIGRmICU+JSBtdXRhdGVfYXQoIkZ1bWEiLCBmYWN0b3IpDQpsZXZlbHMoZGYkRnVtYSlbMV0gPC0gIjAiDQpsZXZlbHMoZGYkRnVtYSlbMl0gPC0gIjEiDQpkZg0KYGBgDQoNCg0KIyBQcmVzZW50YWNpw7NuIGRlIFRhYmxhcyBlIEluZm9ybWVzIGJvbml0b3MNCg0KVmFtb3MgYSB2ZXIgZGlzdGludGFzIGZvcm1hcyBkZSBwcmVzZW50YXIgdW5hIHNhbGlkYSBkZSB1bmEgdGFibGEgcmVzdW1lbiBtZWpvcmFuZG8gZWwgYXNwZWN0byBiw6FzaWNvLg0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KcmVzdW1lbjElPiUNCiAga2JsKCkgJT4la2FibGVfbWF0ZXJpYWwoZnVsbF93aWR0aD1GQUxTRSkNCmBgYA0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KcmVzdW1lbjEgJT4lDQogIGtibCgpICU+JQ0KICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikNCmBgYA0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KcmVzdW1lbjEgJT4lDQprYmwoY2FwdGlvbiA9ICJIYWNlbW9zIHVuYSBUYWJsYSBkZSBNZWpvciBFc3RpbG8iKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIkNhbWJyaWEiKQ0KYGBgDQoNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpyZXN1bWVuMSAlPiUNCiAga2JsKCkgJT4lDQogIGthYmxlX2NsYXNzaWNfMihmdWxsX3dpZHRoID0gRikNCmBgYA0KDQojIEVzdGlsbyBPc2N1cm8NCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpyZXN1bWVuMSAlPiUNCiAga2JsKCkgJT4lDQogIGthYmxlX21hdGVyaWFsX2RhcmsoKQ0KYGBgDQoqKnRpZHlyKioNCg0KPHNwYW4gc3R5bGU9ImNvbG9yOiMyOThBMDgiPmdhdGhlcigpPC9zcGFuPg0KDQo8c3BhbiBzdHlsZT0iY29sb3I6IzI5OEEwOCI+c3ByZWFkKCk8L3NwYW4+DQoNCjxzcGFuIHN0eWxlPSJjb2xvcjojMjk4QTA4Ij5zZXBhcmF0ZSgpPC9zcGFuPg0KDQo8c3BhbiBzdHlsZT0iY29sb3I6IzI5OEEwOCI+dW5pdGUoKTwvc3Bhbj4NCg0KKipkcGx5cioqDQoNCjxzcGFuIHN0eWxlPSJjb2xvcjojREYzQTAxIj5zZWxlY3QoKTwvc3Bhbj4NCg0KPHNwYW4gc3R5bGU9ImNvbG9yOiNERjNBMDEiPmZpbHRlcigpPC9zcGFuPg0KDQo8c3BhbiBzdHlsZT0iY29sb3I6I0RGM0EwMSI+Z3JvdXBfYnkoKTwvc3Bhbj4NCg0KPHNwYW4gc3R5bGU9ImNvbG9yOiNERjNBMDEiPnN1bW1hcmlzZSgpPC9zcGFuPg0KDQo8c3BhbiBzdHlsZT0iY29sb3I6I0RGM0EwMSI+YXJyYW5nZSgpPC9zcGFuPg0KDQo8c3BhbiBzdHlsZT0iY29sb3I6I0RGM0EwMSI+am9pbigpPC9zcGFuPg0KDQo8c3BhbiBzdHlsZT0iY29sb3I6I0RGM0EwMSI+bXV0YXRlKCk8L3NwYW4+DQoNCg0KRWwgYXJjaGl2byBmbGlnaHRzIGVzdMOhIGRpc3BvbmlibGUgZW4gUiB5IGNvbnRpZW5lIGluZm9ybWFjacOzbiByZWxhdGl2YSBhIHNhbGlkYXMgZGUgdnVlbG9zIGRlIE5ZQyBlbiAyMDEzDQoNCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQpmbGlnaHRzICU+JQ0KICAgc2VsZWN0KHllYXIsIG1vbnRoLCBkYXksIGhvdXIsIG1pbnV0ZSkNCmBgYA0KIyBBcm1hbW9zIHVuYSBmZWNoYSBhIHBhcnRpciBkZSB0cmVzIHZhcmlhYmxlcw0KYGBge3IsY29sbGFwc2U9VFJVRX0NCmZsaWdodHMgJT4lDQogIHNlbGVjdCh5ZWFyLCBtb250aCwgZGF5LCBob3VyLCBtaW51dGUpICU+JQ0KICAgIG11dGF0ZShob3JhX3BhcnRpZGEgPSBtYWtlX2RhdGV0aW1lKHllYXIsIG1vbnRoLCBkYXksaG91cixtaW51dGUpDQogICkNCmBgYA0KIyBGdXNpb25hIHRyZXMgY29sdW1uYXM6IHllYXIsIG1vbnRoIHkgZGF5IGVuIHVuYSBudWV2YSBjb2x1bW5hICJmZWNoYSIuDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KDQp2dWVsb3M8LWZsaWdodHMgJT4lIHVuaXRlKCJmZWNoYSIsIHllYXIsbW9udGgsIGRheSwgc2VwID0gIi8iKQ0KdnVlbG9zDQpgYGANCiMgTGEgZnVuY2nDs24gc2VwYXJhdGUoKSBzZXBhcmEgZW4gZG9zIGNvbHVtbmFzICBsYSBmZWNoYQ0KDQpgYGB7cix3YXJuaW5nPUZBTFNFLGNhY2hlPUZBTFNFLG1lc3NhZ2U9RkFMU0UsY29sbGFwc2U9VFJVRX0NCnZ1ZWxvcyAlPiUNCiAgc2VwYXJhdGUoZmVjaGEsIGludG8gPSBjKCJhw7FvIiwgIm1lcyIpKQ0KDQp2dWVsb3MgJT4lDQogIHNlcGFyYXRlKGZlY2hhLCBpbnRvID0gYygiYcOxbyIsICJtZXMiKSklPiUNCiB1bml0ZSgiY2FtcG8iLGHDsW8sbWVzLHNlcD0iLSIpDQpgYGANCiMgVmFtb3MgYSB2ZXIgY29tbyBkYXJsZSBudWV2YSBmb3JtYSBhIHVuYSBiYXNlIGRlIGRhdG9zIHNlZ8O6biBlbCBhbsOhbGlzaXMgcXVlIHF1ZXJyYW1vcyBpbXBsZW1lbnRhciBwdWVkZSBzZXIgbmVjZXNhcmlvDQoNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCiNDYXJnYW1vcyBkb3MgYmFzZXMgZGUgZGF0b3M6IGxhIHByaW1lcmEgdGllbmUgZWwgbm9tYnJlIHkgZWwgYXBlbGxpZG8gZGUgbG9zIG3DunNpY29zIGNvbmp1bnRhbWVudGUgY29uIGVsIA0KI2luc3RydW1lbnRvIHF1ZSBlamVjdXRhbiBwcmluY2lwYWxtZW50ZS4NCg0KYXJ0aXN0c0tIIDwtIHRpYmJsZShmaXJzdCA9IGMoIkppbW15IiwgIkdlb3JnZSIsICJNaWNrIiwgIlRvbSIsICJEYXZ5IiwgIkpvaG4iLCAiUGF1bCIsICJKaW1teSIsICJKb2UiLCAiRWx2aXMiLCAiS2VpdGgiLCAiUGF1bCIsICJSaW5nbyIsICJKb2UiLCAiQnJpYW4iLCAiTmFuY3kiKSwgbGFzdCA9IGMoIkJ1ZmZldHQiLCAiSGFycmlzb24iLCAiSmFnZ2VyIiwgIkpvbmVzIiwgIkpvbmVzIiwgIkxlbm5vbiIsICJNY0NhcnRuZXkiLCAiUGFnZSIsICJQZXJyeSIsICJQcmVzbGV5IiwgIlJpY2hhcmRzIiwgIlNpbW9uIiwgIlN0YXJyIiwgIldhbHNoIiwgIldpbHNvbiIsICJXaWxzb24iKSwgaW5zdHJ1bWVudCA9IGMoIkd1aXRhciIsICJHdWl0YXIiLCAiVm9jYWxzIiwgIlZvY2FscyIsICJWb2NhbHMiLCAiR3VpdGFyIiwgIkJhc3MiLCAiR3VpdGFyIiwgIkd1aXRhciIsICJWb2NhbHMiLCAiR3VpdGFyIiwgIkd1aXRhciIsICJEcnVtcyIsICJHdWl0YXIiLCAiVm9jYWxzIiwgIlZvY2FscyIpKQ0KYXJ0aXN0cyA8LSBhcnRpc3RzS0gNCmFydGlzdHMlPiVoZWFkKCkNCg0KYGBgDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KIyBMYSBzZWd1bmRhIGJhc2UgdGllbmUgZWwgbm9tYnJlIHkgZWwgYXBlbGxpZG8gZGUgbG9zIGFydGlzdGFzIGNvbmp1bnRhbWVudGUgY29uIGxhIGJhbmRhIGRvbmRlIHNlIGhpY2llcm9uIGZhbW9zb3MuDQoNCmJhbmRzS0ggPC0gdGliYmxlKGZpcnN0ID0gYygiSm9obiIsICJKb2huIFBhdWwiLCAiSmltbXkiLCAiUm9iZXJ0IiwgIkdlb3JnZSIsICJKb2huIiwgIlBhdWwiLCAiUmluZ28iLCAiSmltbXkiLCAiTWljayIsICJLZWl0aCIsICJDaGFybGllIiwgIlJvbm5pZSIpLCBsYXN0ID0gYygiQm9uaGFtIiwgIkpvbmVzIiwgIlBhZ2UiLCAiUGxhbnQiLCAiSGFycmlzb24iLCAiTGVubm9uIiwgIk1jQ2FydG5leSIsICJTdGFyciIsICJCdWZmZXR0IiwgIkphZ2dlciIsICJSaWNoYXJkcyIsICJXYXR0cyIsICJXb29kIiksIGJhbmQgPSBjKCJMZWQgWmVwcGVsaW4iLCAiTGVkIFplcHBlbGluIiwgIkxlZCBaZXBwZWxpbiIsICJMZWQgWmVwcGVsaW4iLCAiVGhlIEJlYXRsZXMiLCAiVGhlIEJlYXRsZXMiLCAiVGhlIEJlYXRsZXMiLCAiVGhlIEJlYXRsZXMiLCAiVGhlIENvcmFsIFJlZWZlcnMiLCAiVGhlIFJvbGxpbmcgU3RvbmVzIiwgIlRoZSBSb2xsaW5nIFN0b25lcyIsICJUaGUgUm9sbGluZyBTdG9uZXMiLCAiVGhlIFJvbGxpbmcgU3RvbmVzIikpDQpiYW5kc0tIJT4laGVhZCgpDQpgYGANCg0KIyBKdW50YW1vcyBkb3MgYmFzZXMgdXRpbGl6YW5kbyB1bmEgbyBkb3MgdmFyaWFibGVzIGVuIGNvbcO6biBjb24gbGVmdF9qb2luKCkNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCmJhbmRzMiA8LSBsZWZ0X2pvaW4oYmFuZHNLSCwgYXJ0aXN0cywgYnkgPSBjKCJmaXJzdCIsICJsYXN0IikpDQpiYW5kczIgJT4lIGhlYWQoKQ0KYGBgDQoNCg0KDQojICoqPHNwYW4gc3R5bGU9ImNvbG9yOiNERjNBMDEiPiBPYnNlcnZlbiBRdcOpIGRpZmVyZW5jaWEgaGF5IGNvbiByaWdodF9qb2luKCkgPC9zcGFuPioqDQoNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCg0KYmFuZHMzIDwtIHJpZ2h0X2pvaW4oYXJ0aXN0cywgYmFuZHNLSCwgYnkgPSBjKCJmaXJzdCIsICJsYXN0IikpDQpiYW5kczMgJT4laGVhZCgpDQphcnRpc3RzDQpiYW5kc0tIDQpgYGANCmBgYHtyLGNvbGxhcHNlPVRSVUV9DQojIGlubmVyX2pvaW4gc29sbyByZXRpZW5lIGxhcyBmaWxhcyBxdWUgZXN0YW4gZW4gYW1iYXMgYmFzZXMNCmJhbmRzNCA8LSBpbm5lcl9qb2luKGJhbmRzS0gsIGFydGlzdHMsIGJ5ID0gYygiZmlyc3QiLCAibGFzdCIpKQ0KYmFuZHM0IA0KYGBgDQoNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCiMgZnVsbF9qb2luIHJldGllbmUgbGFzIGZpbGFzIGRlIGN1YWxxdWllcmEgZGUgbGFzIGJhc2VzIGF1bnF1ZSBubyBlc3TDqW4gZW4gbGEgb3RyYQ0KDQpiYW5kczUgPC0gZnVsbF9qb2luKGJhbmRzS0gsIGFydGlzdHMsIGJ5ID0gYygiZmlyc3QiLCAibGFzdCIpKQ0KYmFuZHM1DQpgYGANCg0KDQoNCiMgUGFzYW5kbyBkZSBmb3JtYXRvIGFuY2hvIGEgZm9ybWF0byBsYXJnbyB5IHZpY2V2ZXJzYQ0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KIyBFbiBlc3RhIHByaW1lcmEgYmFzZSBoYXkgdHJlcyBjb2x1bW5hcyBwYXJhIGNhZGEgZW1wbGVhZG8gZW4gbGFzIGNvbHVtbmFzIGVzdMOhbiBsb3Mgc2FsYXJpb3MgbWVkaW9zIGRlIHRyZXMgYcOxb3MgZGUgdHJhYmFqbw0KZGF0YV8yIDwtIGRhdGEuZnJhbWUoIm5hbWVzIiA9IGMoIlBlZHJvIiwgIkNhcmxhIiwgIk1hcnRhIiksIA0KICAgICAgICAgICAgICAgICAgICAgICJXXzIwMTQiID0gYygxMDAsIDQwMCwgMjAwKSwgDQogICAgICAgICAgICAgICAgICAgICAgIldfMjAxNSIgPSBjKDUwMCwgNjAwLCA3MDApLA0KICAgICAgICAgICAgICAgICAgICAgICJXXzIwMTYiID0gYygyMDAsIDI1MCwgOTAwKSApDQoNCmRhdGFfMg0KYGBgDQoNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCiMgRW4gZXN0YSBzZWd1bmRhIGJhc2UgZXN0YW4gbG9zIG1pc21vcyBkYXRvcyBwZXJvIGFob3JhIHBhcmEgY2FkYSBhw7FvIHkgcGFyYSBjYWRhIGVtcGxlYWRvIGhheSB1biByZWdpc3RybyBkb25kZSBlc3RhIHN1IHNhbGFyaW8NCmRhdGFfMyA8LSBkYXRhLmZyYW1lKG5hbWVzID0gYygiUGVkcm8iLCAiQ2FybGEiLCAiTWFydGEiLCAiUGVkcm8iLCAiQ2FybGEiLCAiTWFydGEiLCAiUGVkcm8iLCAiQ2FybGEiLCAiTWFydGEiKSwgIHllYXIgPSBjKCIyMDE0IiwgIjIwMTQiLCAiMjAxNCIsICAiMjAxNSIsICIyMDE1IiwgIjIwMTUiLCAgIjIwMTYiLCAiMjAxNiIsICIyMDE2IiksIHNhbGFyaW8gPSBjKDEwMCwgNDAwLCAyMDAsIDUwMCwgNjAwLCA3MDAsIDIwMCwgMjUwLDkwMCkpDQoNCmRhdGFfMw0KDQpgYGANCiMgTGEgZnVuY2nDs20gZ2F0aGVyKCkgdHJhbnNmb3JtYSBsb3MgZGF0b3MgZGUgZm9ybWF0byBhbmNobyh3aWRlKSBhIGZvcm1hdG8gbGFyZ28obG9uZykNCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCmRhdGFfd2lkZSA8LSBkYXRhXzIgICAjLSBkYXRhXzIgZXN0w6EgZW4gZm9ybWF0byBhbmNobyAod2lkZSkNCg0KZGF0YV9sb25nIDwtIGRhdGFfd2lkZSAlPiUgZ2F0aGVyKHBlcmlvZG8sIHNhbGFyaW8sIDI6NCkgIyAyOjQgc29uIGxhcyBjb2x1bW5hcyBxdWUgdmEgYSBwYXNhciBhbCBvdHJvIGZvcm1hdG8NCiMgcGVyaW9kbyB5IHNhbGFyaW8gc29uIGxvcyBudWV2b3Mgbm9tYnJlcyBkZSBlc2FzIGNvbHVtbmFzDQpkYXRhX2xvbmcNCmBgYA0KIyMgU2kgbWUgbW9sZXN0YSBXXyB5IGxvIHF1aWVybyBzYWNhci4uLnB1ZWRvISENCg0KYGBge3IsY29sbGFwc2U9VFJVRX0NCg0KZGF0YV9sb25nIDwtIGRhdGFfbG9uZyAlPiUgbXV0YXRlKHBlcmlvZG8gPSBzdHJfcmVwbGFjZShwZXJpb2RvLCAiV18iLCAiIiApKSMgbGUgaW5kaWNvIHF1ZSBlbiBsYSBjb2x1bW5hIHBlcmlvZG8gcmVlbXBsYWNlIHdfIHBvciBuYWRhDQpkYXRhX2xvbmcNCmRhdGFfbG9uZyRwZXJpb2RvIDwtIGdzdWIoIldfIiwgIi4iLCBkYXRhX2xvbmckcGVyaW9kbykNCg0KYGBgDQoNCiMjIFBhc2FyIHBhc2FyIGRlIGZvcm1hdG8gbGFyZ28gYSBmb3JtYXRvIGFuY2hvLCB0aWR5ciB0aWVuZSBsYSBmdW5jacOzbiBzcHJlYWQoKQ0KDQpgYGB7cixjb2xsYXBzZT1UUlVFfQ0KZGF0YV93aWRlMiA8LSBkYXRhX2xvbmcgJT4lIHNwcmVhZChwZXJpb2RvLCBzYWxhcmlvKQ0KZGF0YV93aWRlMg0KDQpgYGANCiMgKipFamVyY2NpbyA0KioNCg0KQ29uIGxhcyBiYXNlcyBkZSBkYXRvcyBDbGllbnRlcy54bHN4IHkgUmVnaXN0cm9zLnhsc3ggc2UgcGlkZToNCg0KYSkgU2VwYXJhciBsYSB2YXJpYWJsZSBDbGllbnRlIGVuIGRvcyB2YXJpYWJsZXM6IEFwZWxsaWRvIHkgTm9tYnJlLg0KYikgVW5pciBhbWJhcyB2YXJpYWJsZXMgZW4gdW5hIHNvbGEgcXVlIHNlIGxsYW1lIElEIHkgc2VwYXJhciBhcGVsbGlkbyB5IG5vbWJyZSBjb24gIi0iLg0KYykgVW5pciBsYXMgYmFzZXMgZGUgQ2xpZW50ZXMgeSBSZWdpc3Ryb3MgZGVqYW5kbyBsYXMgZmVjaGFzIGFsIGZpbmFsIHkgZ3VhcmRhcmxvIGVuIHVuYSBudWV2YSBiYXNlLg0KZCkgw41kZW0gcGVybyBkZWphbmRvIGxhIGZlY2hhIGFsIGxhZG8gZGVsIG5vbWJyZSB5IGd1YXJkYXJsbyBlbiB1bmEgbnVldmEgYmFzZS4NCmUpIFNlbGVjY2lvbmFyIGRlIGxhIHVsdGltYSBiYXNlLCBsb3MgcmVnaXN0cm9zIGNvcnJlc3BvbmRpZW50ZXMgYSBQSU1FUyB5IGVsZWdpciBhIGxvcyDDumx0aW1vcyAxMCBxdWUgc2UgYXRlbmRpw7MsIGd1YXJkYXJsbyBlbiB1bmEgdGFibGEgeSBwcmVzZW50YXIgdW5hIHRhYmxhIGJvbml0YSBjb21vIHNhbGlkYQ0KDQoNCg0KDQojICoqRWplcmNpY2lvIDUqKg0KDQpDb24gbG9zIGRhdG9zIGRlIGxhIGJhc2UgY29uc3Vtb19veGlnZW5vLnhsc3gNCmEpIENvbG9jYXIgZW4gdW5hIHZhcmlhYmxlIGVsIGTDrWEgeSBlbiBsYSBvdHJhIGVsIGNvbnN1bW8uIEd1YXJkYXIgZW4gdW5hIG51ZXZhIGJhc2UgZGUgZGF0b3MuDQpiKSBBIGxhIG51ZXZhIGJhc2UgZGUgZGF0b3Mgdm9sdmVybGEgYWwgZm9ybWF0byBhbnRlcmlvci4NCg0KDQoNCg==